application(:didFinishLaunchingwithOptions:) does not get called if apps is killed and opened immediately

827 views Asked by At

I have noticed that if I kill the app from the multitasking view and open it immediately application(:didFinishLaunchingwithOptions:) lifecycle method is not called but the sceneDelegate's scene(:willConnectTo:) method is called.

As far as I know, the above implies the app is not deinitialised and still in memory even after killing and reopening the app.

And because of the above behaviour the NSPersistentContainer object is still in memory and my Core Data stack setup code is present in scene(:willConnectTo:), so it's again initialised and it causes a crash with the following error :

Failed to load the Persistent Store due to: Optional(Error Domain=NSCocoaErrorDomain Code=134081 "(null)" UserInfo={NSUnderlyingException=Can't add the same store twice})

Here is my Core Data Stack setup:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        
        // Show splash screen
        let viewController = UIStoryboard(name: "AppLoading", bundle: Bundle.main).instantiateViewController(withIdentifier: "AppLoadingViewController")
        window.rootViewController = viewController
        
        CoreDataManager.shared.setup {
            // Always present the UI from a Main Thread
            DispatchQueue.main.async {
                if AppSettings.shared.onboardingFinished {
                    self.presentHomeUI(using: window)
                } else {
                    self.presentOnboardingUI(using: window)
                }
            }
        }

         self.window = window
         window.makeKeyAndVisible()
    }
}

Is this normal behaviour of application(:didFinishLaunchingwithOptions:) not called when app is killed an opened immediately ? another mystery is that this issue only affects iPhone X and above at least according to our crash logs.

If the above behaviour cannot be avoided then which method should be an ideal place for Core Data Setup ?

Here is a video of the crash that I am able to reproduce on a device: https://file.re/2021/05/07/sampleprojectappcrashvideo/

And here is a sample project that I created which demonstrate the crash: https://github.com/nik6018/CrashDemo (can only reproduce crash on iPhone X and above)

1

There are 1 answers

0
Nikhil Muskur On

So I filled a DTS for the above issue with Apple as nothing on the internet helped me in understanding this issue.

So here's what Apple said:

  • Whenever the app is swiped away from the multitasking menu, the iOS disconnects and releases the scene.
  • If the app doesn't has anymore scenes, iOS kills the app from memory
  • But iOS doesn't do the above step immediately, so if I open the app quickly again it just creates a new scene and attaches it to the existing app instance
  • And since my Core Data setup is in the scene(:willConnectTo:) method the app crash as I am trying to initialise the store again even though an existing store is already present in memory.

To resolve this issue I have 2 choices:

  1. Move my Core Data Setup in App Delegate

  2. Deinit my Core Data Manager when the app calls sceneDidDisconnect(_:)

I went with option 2. and everything works as expected.

Honestly if I had watched the WWDC19 videos I wouldn't had to waste my DTS ticket :(

Hope this helps anyone if they come across this behaviour.