使用故事板时如何为第一个屏幕的视图控制器进行依赖注入?

时间:2014-09-11 11:42:13

标签: ios objective-c dependency-injection storyboard

手动编写代码时,我们可以通过 AppDelegate 中的构造函数注入向rootViewController注入依赖项:

UIViewController *vc = [[SomeViewController alloc] initWithDependency: dependency];
self.window.rootViewController = vc;

但是,在使用 Storyboard 时,我找不到注入依赖项的方法。在awakeFromNibviewDidLoad等中注入它们似乎是不合适的。

可以注射它们吗?

2 个答案:

答案 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
   }
}

Hook the @IBSegueAction in Interface Builder

(不要忘记选择器名称末尾的':')

这样,您可以使视图控制器代码完全不存在控制器与控制器之间的关系。

我喜欢将所有segues动作都保存在与故事板相同目录中的单个文件中。如果我更改情节提要,我将更改segue动作,而不是控制器...

Keep @IBSegueAction with your Storyboard, not your controller