首页 > 解决方案 > 使用 Storyboard 和自定义视图控制器初始化

问题描述

当以编程方式推送视图控制器时,可以通过 init 方法轻松地进行一些依赖注入:

let dummyVC = DummyVC(dummyManager: DummyManager())
self.pushViewController(dummyVC, animated: true)

使用目标控制器:

class DummyVC: UIViewController {
    private let dummyManager: DummyManager

    init(dummyManager: DummyManager) {
        self.dummyManager = dummyManager
        super.init(nibName: nil, bundle: nil)
    }
}

前面的代码很好,因为它正确地封装了属性,并且清楚地显示了对外部 API 的依赖关系。

使用 Storyboard 时,我们不能选择调用的 init 方法(调用自定义的 init 方法)。

let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let dummyVC = mainStoryboard.instantiateViewControllerWithIdentifier("DummyVC") as! DummyVC
dummyVC.dummyManager = DummyManager() // ERROR: would require dummyManager to have public scope

有没有办法以相同的方式注入依赖项,同时保持属性私有和常量(let)?

标签: swiftdependency-injection

解决方案


故事板中的视图控制器总是使用初始化

init?(coder aDecoder: NSCoder)

没有办法解决这个问题。

另一种选择是……</p>

class DummyVC: UIViewController {
    private var dummyManager: DummyManager!

    func configure(dummyManager: DummyManager) {
        self.dummyManager = dummyManager
    }
}

然后……</p>

let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let dummyVC = mainStoryboard.instantiateViewControllerWithIdentifier("DummyVC") as! DummyVC
dummyVC.configure(dummyManager: DummyManager())

或者

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    switch segue.destination {
    case let dummyVC as DummyVC:
        dummyVC.configure(dummyManager: DummyManager())
    default: 
        break
    }
}

虽然不是完美的(使用let而不是var)属性,private并且隐式展开的可选意味着必须设置它(否则应用程序将在使用时崩溃),并且只能在包含类中发生。

我在整个应用程序中都采用了这一点,并发现它是确保设置所有属性的好方法。只需记住configure在将属性添加到类时更新 func。


推荐阅读