iosswiftmvvmappdelegateproperty-injection

How to properly do property injection of an object in AppDelegate.swift


I try to create an instance of RootViewModel once by injecting it in the RootViewController when the app launches, in the didFinishLaunchingWithOptions of AppDelegate.swift so it doesn't get created multiple times.

Here's the code snippet:

...

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
    }

...

The RootViewModel is a basic swift class with no implementation yet, and the RootViewController has an optional viewModel property to allow for the injection.

var viewModel: RootViewModel?

Here's my issue: Each time I run the app, it stops at the fatalError which I created to know if everything went well with the creation of the rootViewController. So, it means everything didn't go well.

I think the window property is still null at time of creating the rootViewController, but I am not sure how to resolve this.

I have tried creating the same thing in the SceneDelegate with no success.

What can I do to resolve this issue? I am using XCode Version 12.5


Solution

  • 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 function.

    This is because your app may no longer have a single window, but may have multiple windows if you, for example, support multiple views on 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()
        }
    }