0

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?!

mfaani
  • 33,269
  • 19
  • 164
  • 293

1 Answers1

1

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.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thank you for the extra historical detail. I don't understand your edit. Can you elaborate a bit more? – mfaani Mar 12 '21 at 19:22
  • 1
    Let me put it differently. :) Launching in the background is still launching. We could come into the foreground later, and the app better be in the right state. How's that going to happen if view controller lifetime messages were suppressed during launch? The app is the app; actual physical visibility to the user is irrelevant from that standpoint. – matt Mar 12 '21 at 19:26
  • What causes the viewcontroller life cycle events to trigger? I mean if I just do let vc = UIViewController()` I won't get any of its lifecycle events called. EDIT: I just commented out the line call to `makeKeyAndVisible` and after that a launch in the background didn't cause any life cycle events. – mfaani Mar 12 '21 at 19:47
  • yeah well you'd never do that in real life; if you happened to launch in the foreground there would be no interface, surely you don't want that – matt Mar 12 '21 at 20:29
  • My code doesn't have any extra logic to return `false` for `didFinishLaunching`, but often I see logs that show `didFinishLaunching` was reached, but then the `viewDidLoad` of my root VC isn't called. Is there any explanation you can think of? – mfaani Nov 05 '21 at 19:28
  • Show your root vc code (in a new question). – matt Nov 05 '21 at 19:31
  • Whoops. I just saw that our nav stack was much more complicated than what I thought. The rootVC is getting called. Not sure why the other isn't... – mfaani Nov 05 '21 at 20:19