如何使用依赖注入和工厂模式实现 ViewController 自定义初始化?

How to Implement ViewController custom init using dependency injection and factory patterns?

我正在尝试使用 DI 和工厂实现简单示例。

ViewController.swift

class VIewController : UIViewController {
    private let factory: ViewControllerFactory

    init(with factory: Factory) {
        self.factory = factory
        super.init(nibName: nil, bundle: nil)
    }
}

protocol ViewControllerFactory {
    func makeViewController() -> ViewController

}

class DependencyContainer {
   /// 
}

extension DependencyContainer: ViewControllerFactory {
    func makeViewController() -> ViewController {
        return ViewController(with: self)

    }
}

AppDelegate.swift

func application(_ application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: 
    [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

self.window = UIWindow(frame: UIScreen.main.bounds)
    let container = DependencyContainer()
    let rootViewController = container.makeViewController()

    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()

    return true
}

我在故事板中设计了视图控制器。我如何才能成功将我的代码更正为 运行 应用程序?

应用崩溃:

您所描述的行为是故事板的工作方式(即它们称为 initWithCoder)。如果您需要调用您的构造函数,您可以使用一个 nib 文件,然后调用您的构造函数,该构造函数调用 init(nibName:bundle:) 并将正确加载 nib 文件。这适用于当前 iOS 版本。

通过故事板获取构造函数注入的唯一方法是使用 iOS 13 并使用新的 @IBSegueAction ,这将为您提供一个编码器,您可以将其传递给构造函数然后调用 super initWithCoder.

有不同类型的依赖注入。您目前正在尝试使用基于构造函数的依赖注入,不幸的是,它实际上不适用于情节提要,因为它们需要使用解码器进行初始化。 iOS 13 确实引入了一些使这种方法成为可能的附加功能,但目前,您可以改用基于 setter 的依赖项注入。

类似于以下内容:

class ViewController: UIViewController {
    var factory: ViewControllerFactory!
}

protocol ViewControllerFactory {
    func makeViewController() -> ViewController
}

class DependencyContainer {
    let storyboard: UIStoryboard = UIStoryboard(name: "Storyboard", bundle: Bundle.main)
}

extension DependencyContainer: ViewControllerFactory {
    func makeViewController() -> ViewController {
        guard let vc = storyboard.instantiateViewController(withIdentifier: "ViewController") as? ViewController else {
            fatalError("Unrecognised viewController")
        }
        vc.factory = self
        return vc
    }
}

在iOS13中,你可以初始化一个故事板视图控制器如下:

为您的 ViewController class

添加初始化程序
let property: Property // Your injected property

required init?(coder: NSCoder, property: Property) {
    self. property = property
    super.init(coder: coder)
}

required init?(coder: NSCoder) { // You'll need to add this 
    fatalError("init(coder:) has not been implemented")
}

在你的工厂class:

let viewController = storyboard.instantiateViewController(identifier: "ViewController") { coder in
    ViewController(coder: coder, property: <injected property>)
}