Swinject注入自身的财产到新的UIViewController
让我们假设我们有一个UITableViewController
上didSelectRowAtSection
加载一个类的实例,即命名为:ClassToInject
,并希望通过物业注入注入,因为我们ViewControllerToBePushed
有ClassToInject
的属性,即随后在didSet
回调(因为它是一个UITabBarViewController
),它搜索符合ClassToInjectPresentable
简单,因为它所有的财产viewControllers
:Swinject注入自身的财产到新的UIViewController
protocol ClassToInjectPresentable {
var property: ClassToInject { get set }
}
到现在为止,我只想做这样的事情:
func didSelectRowAtIndexPath {
let classToInject = self.loadClassToInjectFor(indexPath)
let tabBarViewController = SomeTabBarViewController()
tabBarViewController.property = classToInject
self.navigationController.push(tabBarViewController, animated: true)
}
而且在SomeTabBarViewController
...
class SomeTabBarViewController: ClassToInjectPresentable {
var property: ClassToInject? {
didSet(newValue) {
self.viewControllers.filter{ $0 is ClassToInjectPresentable }.map{ $0 as! ClassToInjectPresentable }.forEach{ $0.property = newValue }
}
}
,一切都应该得到加载好和容易(但它不是)。我已阅读Swinject
,这可能会解决它。我见过很多例子注册了诸如:
container.register(Animal.self) { _ in Cat(name: "Mimi") }
但我不知道我是否可以注册在self
加载某些属性:
container.register(ClassToInjectInjector.self) { _ in
self.loadClassToInjectFor(indexPath) }
// And then
container.register(ClassToInjectPresentable.self) { _ in
SomeTabBarViewController() }
.initCompleted { r, p in
let tabBar = p as! SomeTabBarViewController
tabBar.property = r.resolve(ClassToInjectInjector.self)
// And lastly?
self.navigationController.pushViewController(tabBar, animated: true)
}
}
最后,我按照提出的建议得到了最终的答案。
public class Containers {
fileprivate init() { }
}
extension Containers {
static let activityPresentableContainer: Container = {
let container = Container()
container.register(ActivityTabBarController.self) { (r: Resolver, arg1: Activity) in
return ActivityTabBarController(activity: arg1)
}
container.register(ActivityPresentable.self) {
(r: Resolver, arg1: ActivityPresentableTabs, arg2: Activity) in
switch arg1 {
case .summary:
return ActivitySummaryViewController(activity: arg2)
case .detail:
return ActivityDetailPageViewController(activity: arg2)
case .map:
return ActivityMapViewController(activity: arg2)
case .charts:
return ActivityChartsViewController(activity: arg2)
case .strava:
return ActivityStravaViewController(activity: arg2)
}
}.inObjectScope(.transient)
return container
}()
通过这种方法,命名ActivityTabBarController
得到总是由activityPresentableContainer
使用下面的语句实例:
let controller = Containers.activityPresentableContainer.resolve(
ActivityTabBarController.self, argument: activity
)!
然后,每个TabBarController内的卡的使用所需的参数被实例化Activity
和使用.transient
上下文的选项卡类型。它解决这样的:
let activitySummary = Containers.activityPresentableContainer.resolve(
ActivityPresentable.self, arguments: ActivityPresentableTabs.summary, activity!
) as! UIViewController
这样我可以概括取决于只是,他们正在使用的信息标签栏的选项卡。如果其中一个选项卡随时更改,我可以按照ActivityPresentable
协议更改注册。
这是很难推荐合适的解决方案,而知道你的应用程序的细节,但这里有一些建议:
container.register(ClassToInjectInjector.self) { _ in
self.loadClassToInjectFor(indexPath)
}
一般来说,所有register
-ations应你的对象之外进行。常见的设置有一个全局的Container
,其中包含所有注册 - 您应该将它们看作指令来构建没有任何隐式上下文的应用程序对象。如果你的依赖需要在UITableViewController
被创建,你可以将它传递给resolve
方法作为参数:
container.register(ClassToInjectPresentable.self) { resolver, property in
let tabBar = SomeTabBarViewController()
tabBar.property = property
return tabBar
}
// in UItableVIewController
container.resolve(ClassToInjectPresentable.self,
argument: self.loadClassToInjectFor(indexPath))
而且这通常是一个坏主意:
.initCompleted { r, p in
...
self.navigationController.pushViewController(tabBar, animated: true)
}
你不应该混合应用程序逻辑与DI - 使用Swinject纯粹是为了构建你的依赖关系。
所以你UITableViewController
可能是这个样子:
func didSelectRowAtIndexPath {
let classToInject = self.loadClassToInjectFor(indexPath)
let tabBar = container.resolve(
SomeTabBarViewController.self, argument: loadClassToInjectFor(indexPath)
)
navigationController.push(tabBar, animated: true)
}
至于你TabBar
和视图控制器:怎么办UIViewControllers
进入TabBar
?是否有可能做这样的事情?
class SomeTabBarViewController {
init(viewControllers: [UIViewController]) {
...
}
}
container.register(SomeTabBarViewController.self) { r, property
SomeTabBarViewController(viewControllers:[
r.resolve(MyViewController.self, argument: property),
r.resolve(MyViewController2.self, argument: property)
])
}
'tabBar.property = injector'从哪里来? –
对不起,它的意思是'tabBar.property = property'。我已经更新了一个答案 –