Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/swinject storyboard ability to pass arguments to vc #112

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1833160
implemented ability to add arguments to inject them to UIViewControllers
Aug 10, 2017
2008562
updated pod spec
Aug 10, 2017
e182cbe
fixed acces control
Aug 10, 2017
6c8dddd
added 3 arguments to SwinjectStoryboard
Aug 11, 2017
fa8cd96
fixed bugs connected to passing 3 arguments to VC
Aug 11, 2017
ab28482
Updated Readme
Aug 11, 2017
f582e1b
Fixed readme
Aug 11, 2017
7cfd87e
Fixed arguments retaining while using 'storyboardInitCompletedArgs' f…
andreybog Jul 30, 2018
f9267d2
Fixed missed argument type.
andreybog Jul 30, 2018
ffd6330
Fix compilation on OSX
andreybog Jul 30, 2018
a17f7ba
Merge branch 'master' into master
andreybog Jul 31, 2018
679e157
Update README.md
andreybog Jul 31, 2018
8543be2
Added Nimble and Quick to Cartfile.
andreybog Jul 31, 2018
39040e8
Merge branch 'master' of https://github.com/SeductiveMobile/SwinjectS…
andreybog Jul 31, 2018
c144701
Fixed OSX Compilation.
andreybog Jul 31, 2018
cac17fb
Fixed tests.
andreybog Jul 31, 2018
33f45f1
Update README.md
andreybog Aug 2, 2018
14ae7ec
Update dependency version on 'Swinject'.
andreybog Sep 21, 2018
c9644a5
added autogenerated code for arguments calls, added tests
alayers2 Oct 22, 2018
ae08713
Merge branch 'master' into feature/swinject-storyboard-ability-to-pas…
alayers2 Oct 22, 2018
a7b8685
change source in podspec
alayers2 Oct 22, 2018
4a03a98
Merge branch 'feature/swinject-storyboard-ability-to-pass-arguments-t…
alayers2 Oct 22, 2018
b5ef3f5
update readme, changed childViewControllers -> children in autogen code
alayers2 Oct 22, 2018
5812076
Corrected children view controller naming issue
alayers2 Oct 29, 2018
2b91fe7
Travis could not resolve Swinject dependency in podspec, bumping down…
alayers2 Oct 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -221,6 +221,30 @@ container.register(Animal.self) { _ in Cat(name: "Mimi") }

If you implicitly instantiate `UIWindow` and its root view controller, the registrations setup for "Main" storyboard can be shared with the referenced storyboard since `defaultContainer` is configured in `setup` method.

### Arguments
if you want to pass some arguments, you can do it in such way:

1) Register VC
```swift
let container = SwinjectStoryboard.defaultContainer
container.storyboardInitCompletedArgs(AnimalViewController.self) { (r, c, arguments: (Int, SomeValue)) in
c.animal = r.resolve(Animal.self)
c.countAnimals = arguments.0
c.someValue = arguments.1
}
container.register(Animal.self) { _ in Cat(name: "Mimi") }
```

2) Resolve VC
```swift
let sb = SwinjectStoryboard.create(
name: "Animals", bundle: nil, container: container)
let firstArg: Int = 5
let secondArg: SomeValue = SomeValue()
let catController = sb.instantiateViewController(withIdentifier: "SomeIdentifier", arguments: (firstArg, secondArg)) as! AnimalViewController
```


## Credits

SwinjectStoryboard is inspired by:
155 changes: 155 additions & 0 deletions Sources/SwinjectStoryboard.Arguments.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//
// Created by Andrew Ayers on 10/22/18
// Copyright © 2018 Swinject Contributors. All rights reserved.
//

//
// NOTICE:
//
// SwinjectStoryboard.Arguments.swift is generated from SwinjectStoryboard.Arguments.erb by ERB.
// Do NOT modify SwinjectStoryboard.Arguments.swift directly.
// Instead, modify SwinjectStoryboard.Arguments.erb and run `script/gencode` at the project root directory to generate the code.
//

<% arg_count = 3 %>

import Swinject
#if os(iOS) || os(tvOS)
extension SwinjectStoryboard {
<% (1..arg_count).each do |i| %>
<% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<% arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>

private func injectDependency<<%= arg_types %>>(to viewController: UIViewController, arguments: (<%= arg_types %>) ) {
guard !viewController.wasInjected else { return }
defer { viewController.wasInjected = true }

let registrationName = viewController.swinjectRegistrationName

if let container = container.value as? _Resolver {
let option = SwinjectStoryboardOption(controllerType: type(of: viewController))
typealias FactoryType = ((Resolver, Container.Controller, (<%= arg_types %>))) -> Any
let _ = container._resolve(name: registrationName, option: option) { (factory: FactoryType) in factory((self.container.value, viewController, arguments)) as Any } as Container.Controller?
} else {
fatalError("A type conforming Resolver protocol must conform _Resolver protocol too.")
}

#if swift(>=4.2)
for child in viewController.children {
injectDependency(to: child, arguments: arguments)
}
#else
for child in viewController.childViewControllers {
injectDependency(to: child, arguments: arguments)
}
#endif
}
<% end %>

<% (1..arg_count).each do |i| %>
<% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<% arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>

public func instantiateViewController<<%= arg_types %>>(withIdentifier identifier: String,
arguments: (<%= arg_types %>)) -> UIViewController {
let viewController = loadViewController(with: identifier)
injectDependency(to: viewController, arguments: arguments)
return viewController
}

<% end %>

private func loadViewController(with identifier: String) -> UIViewController {
SwinjectStoryboard.pushInstantiatingStoryboard(self)
let viewController = super.instantiateViewController(withIdentifier: identifier)
SwinjectStoryboard.popInstantiatingStoryboard()
return viewController
}
}
#endif

#if os(OSX)
extension SwinjectStoryboard {
<% (1..arg_count).each do |i| %>
<% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<% arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>

private func injectDependency<<%= arg_types %>>(to viewController: NSViewController, arguments: (<%= arg_types %>) ) {
guard !viewController.wasInjected else { return }
defer { viewController.wasInjected = true }

let registrationName = viewController.swinjectRegistrationName

if let container = container.value as? _Resolver {
let option = SwinjectStoryboardOption(controllerType: type(of: viewController))
typealias FactoryType = ((Resolver, Container.Controller, (<%= arg_types %>))) -> Any
let _ = container._resolve(name: registrationName, option: option) { (factory: FactoryType) in factory((self.container.value, viewController, arguments)) as Any } as Container.Controller?
} else {
fatalError("A type conforming Resolver protocol must conform _Resolver protocol too.")
}

#if swift(>=4.2)
for child in viewController.children {
injectDependency(to: child, arguments: arguments)
}
#else
for child in viewController.childViewControllers {
injectDependency(to: child, arguments: arguments)
}
#endif
}
<% end %>

<% (1..arg_count).each do |i| %>
<% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<% arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>

public func instantiateController<<%= arg_types %>>(withIdentifier identifier: NSStoryboard.SceneIdentifier,
arguments: (<%= arg_types %>)) -> NSViewController {
let viewController = loadController(with: identifier) as! NSViewController
injectDependency(to: viewController, arguments: arguments)
return viewController
}

<% end %>

private func loadController(with identifier: NSStoryboard.SceneIdentifier) -> Any {
SwinjectStoryboard.pushInstantiatingStoryboard(self)
let viewController = super.instantiateController(withIdentifier: identifier)
SwinjectStoryboard.popInstantiatingStoryboard()
return viewController
}
}
#endif

#if os(iOS) || os(OSX) || os(tvOS)
extension Container {
<% (1..arg_count).each do |i| %>
<% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %>
<% arg_description = i == 1 ? "#{i} argument" : "#{i} arguments" %>
/// Adds a registration of the specified view or window controller that is configured in a storyboard.
///
/// - Note: Do NOT explicitly resolve the controller registered by this method.
/// The controller is intended to be resolved by `SwinjectStoryboard` implicitly.
///
/// - Parameters:
/// - controllerType: The controller type to register as a service type.
/// The type is `UIViewController` in iOS, `NSViewController` or `NSWindowController` in OS X.
/// - name: A registration name, which is used to differenciate from other registrations
/// that have the same view or window controller type.
/// - initCompleted: A closure to specifiy how the dependencies of the view or window controller are injected.
/// It is invoked by the `Container` when the view or window controller is instantiated by `SwinjectStoryboard`.

public func storyboardInitCompleted<C: Controller, <%= arg_types %>>(_ controllerType: C.Type,
name: String? = nil, initCompleted: @escaping (Resolver, C, (<%= arg_types %>)) -> ()) {
let factory = { (r: Resolver, c: Controller, arguments: (<%= arg_types %>)) -> Container.Controller in
initCompleted(r, c as! C, arguments)
return c
}

let option = SwinjectStoryboardOption(controllerType: controllerType)
_register(Controller.self, factory: factory, name: name, option: option)
}
<% end %>
}
#endif
Loading