Search code examples
iosuiviewcontrollerviewdidloaduiwindowios-lifecycle

Are viewcontroller llfecycle events suppose to be called when app is launched into background?


I always knew that window?.makeKeyAndVisible() is to be done within didFinishLaunching

But I also thought non of the root viewcontroller’s life cycle events would get called until app is foregrounded. Is thought incorrect?

i.e. by calling makeKeyAndVisible — even when the app is only launched in background I see the viewDidLoad, viewWillAppear and viewDidAppear methods of it getting called.

Is that expected?!


Solution

  • Yes, it is, sort of. "appear" doesn't mean "the user is about to see it". It means "the view controller hierarchy is being assembled and this view controller's view is going into the hierarchy". The view controller calls should be stable regardless of whether we launch in the foreground or background.

    (To see this, imagine the contrary; all hell would break loose! Launching is launching, view controllers are view controllers; you must get the expected events or the app will break.)


    But let me make a stronger warning here, while I have the soapbox. Do not make any assumptions about how two different lifetime cycles will interleave with one another. The app lifetime cycle is stable and the view controller lifetime cycle is stable, but how they interleave with one another varies greatly from major system to major system and from architecture to architecture (by "architecture" I mean that that it matters whether you are using a navigation controller etc.).

    I've got a lot of history with this. When I first started programming iOS I worked out that this was the interleaved order:

    • application(_:didFinishLaunchingWithOptions:)
    • viewDidLoad
    • viewWillAppear(_:)
    • applicationDidBecomeActive(_:)
    • viewDidAppear(_:)

    Relying on that order, I typically used the root view controller's viewDidAppear(_:) to register for UIApplication.didBecomeActiveNotification in order to be notified of subsequent activations of the app.

    That worked fine for some years. But iOS 8 brought with it a momentous change: the app delegate now received applicationDidBecomeActive(_:) after the root view controller received viewDidAppear(_:), like this:

    • application(_:didFinishLaunchingWithOptions:)
    • viewDidLoad
    • viewWillAppear(_:)
    • viewDidAppear(_:)
    • applicationDidBecomeActive(_:)

    This was a disaster for many of my apps, because the notification I had just registered for in viewDidAppear(_:) arrived immediately.

    Then, in iOS 9, the order returned to what it was in iOS 7 and before — knocking my apps into confusion once again. Then, in iOS 11, the order reverted back to what it was in iOS 8!

    The moral is that you should not, as I did, rely upon the timing relationship between lifetime events of different objects. What I was doing was always wrong.