OS X storyboard calls viewDidLoad before applicationDidFinishLaunching

前端 未结 4 771
野趣味
野趣味 2020-12-06 06:28

I created a Mac OS X application in Xcode using storyboards. For some reason the applicationDidFinishLaunching method in the AppDelegate is being called after <

相关标签:
4条回答
  • 2020-12-06 06:52

    The other solution is registering NSApplicationDidFinishLaunchingNotification in your view controllers and move your code from viewDidLoad to applicationDidFinishLaunchingNotification:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidFinishLaunchingNotification:)
                                                 name:NSApplicationDidFinishLaunchingNotification
                                               object:nil];
    
    0 讨论(0)
  • 2020-12-06 06:59

    Correct, the lifecycle is a wee bit different in OS X.

    Instead of letting the storyboard be your initial interface (this is defined in the General settings of your project), you can instead set up a MainMenu xib file and designate that as your main interface, then in your applicationDidFinishLaunching method in your AppDelegate you can programmatically instantiate your storyboard after you have completed your other initialization code.

    I recommend checking out Cocoa Programming for OS X: The Big Nerd Ranch Guide if you haven't already; one nice thing they do in their book is actually have you get rid of some of the default Xcode template stuff and instead they have you set up your initial view controller the "right" way by doing it explicitly.

    You might put something like this in your applicationDidFinishLaunching:

    NSStoryboard *mainStoryboard = [NSStoryboard storyboardWithName:@"Main" bundle:nil];
    MyWindowController *initialController = (MyWindowController *)[mainStoryboard instantiateControllerWithIdentifier:@"myWindowController"];
    [initialController showWindow:self];
    [initialController.window makeKeyAndOrderFront:self];
    

    This assumes that you've already changed "Main Interface" to something like MainMenu.xib.

    0 讨论(0)
  • 2020-12-06 07:10

    As the question's author mentioned:

    The app does not crash but now the window never appears.

    Despite Nicolas and Aaron both helpful answers (I already adquire the book you recommended, Aaron, and will start implementing the two-storyboard pattern your way, Nicolas), neither solve the specific problem of the window not showing.

    Solution

    You need make your WindowController instance live outside applicationDidFinishLaunching(_:)'s scope. To accomplish it, you could declare a NSWindowController propriety for your AppDelegate class and persist your created WindowController instance there.

    Implementation

    In Swift 4.0

    import Cocoa
    
    @NSApplicationMain
    class AppDelegate: NSObject, NSApplicationDelegate {
    
        var mainWindowController: NSWindowController?
    
        func applicationDidFinishLaunching(_ aNotification: NSNotification) {
    
            let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
            let mainWindow = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "MainWindow")) as! NSWindowController
            mainWindow.showWindow(self)
            mainWindow.window?.makeKeyAndOrderFront(self)
    
            // After applicationDidFinishLaunching(_:) finished, the WindowController instance will persist.
            self.mainWindowController = mainWindow
        }
    }
    
    0 讨论(0)
  • 2020-12-06 07:11

    In addition to Aaron's answer, I found out that the separate Interface Builder file containing the menu alone (separate from the window and view controller) does not need to be a xib; it too can be a storyboard. This enables us to easily fix as follows:

    1. Duplicate your original storyboard (Main.storyboard) and rename it to "Menu.storyboard"
    2. Delete the window controller and view controller from Menu.storyboard
    3. Delete the app menu bar from Main.storyboard.
    4. Change your app target's "Main Interface" from "Main.storyboard" to "Menu.storyboard".

    (I tried it in my app and it works)

    This avoids having to re-create the app's main menu from scratch, or to figure out how to transplant your existing one from "Main.stroyboard" to "Menu.xib".

    0 讨论(0)
提交回复
热议问题