【问题标题】:How to properly do property injection of an object in AppDelegate.swift如何在 AppDelegate.swift 中正确地进行对象的属性注入
【发布时间】:2021-05-05 08:17:02
【问题描述】:

我尝试创建一次 RootViewModel 的实例,方法是在应用启动时将其注入到 RootViewController 中,在 didFinishLaunchingWithOptions 中>AppDelegate.swift 所以它不会被多次创建。

这里是sn-p的代码:

...

var window: UIWindow?

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

        guard let rootViewController = window?.rootViewController as? RootViewController else {
            fatalError("Unable to Instantiate the root view controller")
        }

        let rootViewModel = RootViewModel()
        
        rootViewController.viewModel = rootViewModel
        
        return true
    }

...

RootViewModel 是一个基本的 swift 类,还没有实现,RootViewController 有一个可选的 viewModel 属性来允许注入。

var viewModel: RootViewModel?

这是我的问题:每次我运行应用程序时,它都会停在我创建的 fatalError 处,以了解创建 rootViewController 是否一切顺利。所以,这意味着一切都不顺利。

我认为在创建 rootViewController 时 window 属性仍然为空,但我不确定如何解决。

我尝试在 SceneDelegate 中创建相同的东西,但没有成功。

我可以做些什么来解决这个问题?我正在使用 XCode 12.5 版

【问题讨论】:

  • 你为什么不把你的 RootViewModel 初始化放到你的 RootViewController 的“viewDidLoad”中呢?
  • 感谢@LukeSideWalker 的建议,但我认为这会导致 RootViewController 和 RootViewModel 之间的紧密耦合。这就是我决定使用 Injection 的原因。
  • 你为什么不尝试在调试器中检查 window?.rootViewController 的内容?也许您只是将 ViewController 放入 UINavigationController,这就是为什么 rootVC 不是您班级的 VC
  • 由于您的 RootViewController 显然是在 InterfaceBuilder 中定义的,并且尚未在“AppDidLaunch”阶段创建,因此您可以在 viewDidLoad 中使用 Notification(由您的 AppDelegate 观察),而不是注入。但这不是最好的架构。我不使用 InterfaceBuilder,这就是为什么我可以在 AppDelegate 中创建 VC,分配给 window.rootViewController 并注入我想要的任何东西。但在你的情况下,使用 IB,我只能想到 Notification 的方式。
  • 如果你想使用这种方法,你需要添加代码来创建UIWindow 并从你的故事板中实例化根视图控制器。仅当windowdidFinishLaunching 返回后为nil 时,才会自动创建这些项目

标签: ios swift mvvm appdelegate property-injection


【解决方案1】:

由于您采用了新的场景生命周期并拥有场景委托,您需要在willConnectTo场景委托函数中访问根视图控制器。

这是因为您的应用可能不再只有一个窗口,而是可能有多个窗口,例如,如果您在 iPadOS 上支持多个视图。


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
     guard let scene = (scene as? UIWindowScene) else { return }
        
     if let rootVC = scene.windows.first?.rootViewController as? RootViewController {
         rootViewController.viewModel = RootViewModel()
    }
}

【讨论】:

  • 成功了。谢谢@Paulw11。你能解释一下为什么必须这样做吗?非常感谢兄弟!
  • 认为你已经提供了原因:Since you have adopted the new scene lifecycle and have a scene delegate, you need to access the root view controller in the willConnectTo scene delegate functionThanks @Paulw11
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
  • 2019-12-17
  • 2014-07-23
相关资源
最近更新 更多