Search code examples
xcodemacosappkit

Why is applicationDidFinishLaunching called after main view's draw method in AppKit


I am used to performing app initialization in applicationDidFinishLaunching in iOS, but in appKit it is getting called after the main view's draw method! It is too early to draw anything since the app hasn't been initialized. Here is the order:

  1. viewDidLoad (main view controller)
  2. draw(_ dirtyRect:) (view of main controller)
  3. applicationDidFinishLaunching (too late!)

The API reference says the following about applicationDidFinishLaunching

This method is called after the application’s main run loop has been started but before it has processed any events.

Thus a draw event should be posted after applicationDidFinishLaunching. I am not used to this behavior -- what is going on?


Solution

  • You're just making a false assumption. The initial view controller's viewDidLoad does fire before applicationDidFinishLaunching is called. That's because the runtime loads the storyboard's initial window controller, and causes its view to be loaded, before calling applicationDidFinishLaunching on the app delegate.

    If you need an event before the main view's draw, implement applicationWillFinishLaunching. But it would be even better, since you now know the actual order of events, to do your application initialization in the main view controller's viewDidLoad, as it is even earlier. After all, if what you draw initially depends on an initialization you perform earlier, viewDidLoad seems to fit perfectly.

    The earliest event you can get in a conventional modern storyboard-based launch is the app delegate's awakeFromNib. But be careful because in macOS it can be called more often than you might expect. (Actually, the class method initialize is even earlier, but be warned that you can't implement that in Swift.)