Trying to show sheet on first app launch

I would like to show a welcome sheet when my app first launches. Starting with a blank Xcode project, I've set up a WelcomeStoryboard how I want it.

I can show it as a sheet using a button click, calling this in my ViewController:

func showWelcome() {
    let welcomeStoryboard = NSStoryboard(name: "WelcomeStoryboard", bundle: nil)

    guard let welcomeViewController  = (welcomeStoryboard.instantiateInitialController() as? NSWindowController)?.contentViewController else {
        return
    }

    self.presentAsSheet(welcomeViewController)
}

However, I am finding it hard to see where I can call that so it will show the sheet when the window first loads.

Inside viewDidLoad is too soon, it seems:

Assertion failure in -[NSViewControllerSheetTransition animatePresentationOfViewController:fromViewController:], NSViewControllerSheetTransition.m:33
Failed to set (contentViewController) user defined inspected property on (NSWindow): self.fromViewController.view.window should be valid!

I noticed that if I wrap presentAsSheet inside DispatchQueue.main.async it works! But I don't understand why that would work, and am reluctant to trust it.

I'm hoping someone can shed some light on this for me? It feels like a trivial requirement but I'm stuck on it!

Replies

show a welcome sheet when my app first launches

Inside viewDidLoad

Do you want to show when app launches or when some VC shows ? Where do you call showWelcome()

Thanks for your help :) I want to show the sheet "when the app launches", meaning specifically when its main window first shows after launching (it's a single window app).

Since I want to present my welcome as a sheet, I need a window in which to show it, so I've tried:

  • calling showWelcome from inside the main ViewController (as provided by the "Main" storyboard in Xcode's default app template), both in viewDidLoad (crashes) and in viewDidAppear (shows the sheet again every time the app becomes visible).
  • from inside applicationDidFinishLaunching — doesn't work as it seems NSApplication.shared.mainWindow is not available yet at this point. Anyway as far as I can see, NSApplication.shared.mainWindow isn't great for this purpose because the user might minimise the app after launching it, but before its main window shows.

I was thinking there must be a nice place in the launch lifecycle for me to call showWelcome. I was looking for somewhere that fires "once the app has launched and we have the main window to work with". I'm starting to think I will just have to put it in the main window's content view controller's viewDidAppear, and maintain an "isFirstAppearance" boolean or some such.

Just as a follow-up; I did indeed end up triggering the sheet from viewDidAppear, with some logic around it to ensure it only happens once, on first appearance. It seems to work fine.

My first attempts at this failed because I was expecting presentAsSheet to work from viewDidLoad or similar; apparently it will only work once the presenting view has appeared... which still seems non-obvious to me, but it is what it is.