Swinject 将自身属性注入新的 UIViewController



让我们假设我们有一个UITableViewController,在didSelectRowAtSection加载一个名为的类的实例,即:ClassToInject并且它希望通过属性注入来注入它,因为我们的ViewControllerToBePushed具有ClassToInject的属性,随后(因为它是一个UITabBarViewController)在didSet回调上,它搜索其所有符合ClassToInjectPresentable简单viewControllers属性:

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)
}
}

在不知道您的应用程序详细信息的情况下,很难推荐正确的解决方案,但这里有一些建议:

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)
])
}

最后,我按照提出的建议得到了最终答案。

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协议更改注册。

相关内容

  • 没有找到相关文章

最新更新