手动编写代码时,我们可以通过 AppDelegate 中的构造函数注入向rootViewController注入依赖项:
UIViewController *vc = [[SomeViewController alloc] initWithDependency: dependency];
self.window.rootViewController = vc;
但是,在使用 Storyboard 时,我找不到注入依赖项的方法。在awakeFromNib
或viewDidLoad
等中注入它们似乎是不合适的。
可以注射它们吗?
答案 0 :(得分:0)
在AppDelegate中测试以下代码:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let dependency = MyDependency()
if let firstVC = window?.rootViewController as? MyViewControllerClass {
firstVC.dependency = dependency
}
return true
}
答案 1 :(得分:0)
要正确进行依赖项注入,您需要做两件事:
1-将数据注入到根视图控制器中。
这可以在MarMass答案中所示的App委托中完成,或者如果您需要一些也适合文档应用程序的内容,则可以按照我在此处接受的答案中的建议进行操作:Can't use storyboard custom instantiated window controller
2-您需要将数据从根视图控制器传递到其后代。
您会发现许多人为此表示“使用prepareForSegue”。我真的不喜欢使用prepeareForSegue,因为当我认为每个视图控制器应该保持独立时,它会创建从根视图控制器到其后代的硬依赖性。
您不能在另一个Storyboard流中重用控制器,而无需一次又一次地修改视图控制器代码(在这种情况下为prepareForSegue)。
此外,如果您有很多关系,则prepareForSegue方法将成为巨大的“案例”代码。始终是我们可以做得更好的指标。
我建议另一种方法:
使用@IBSegueAction创建视图控制器的扩展,并将该@IBSegueAction挂钩到segue视图接口生成器。这适用于过渡序列和嵌入序列。
extension FatherViewController {
@IBSegueAction func injectToTextViewController(_ coder: NSCoder) -> NSViewController? {
// Create the destination view controller
let destinationViewController = TextViewController(coder: coder)!
// Compute here the data to inject to the destination controller. As this is an extension of the father view controller, you have access to all its data
destinationViewModel.data = self.data
return destinationViewController
}
}
(不要忘记选择器名称末尾的':')
这样,您可以使视图控制器代码完全不存在控制器与控制器之间的关系。
我喜欢将所有segues动作都保存在与故事板相同目录中的单个文件中。如果我更改情节提要,我将更改segue动作,而不是控制器...