Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally showing NSViewController at app launch

I'm developing an OSX app where I show first a login/register window if the user hasn't logged in yet.

After login success I show my main view controller.

If the user is already logged in (a token is stored), then the app has to launch directly with the main view controller.

I'm new to OSX development, I googled for this kind of scenario but couldn't find anything.

So I went up with what I think should work. It works sometimes, sometimes I get a blank window.

In the storyboard I let the Main Menu and the Window Controller. I removed the "contains" segue to my main view controller.

In AppDelegate, I put this:

func applicationDidFinishLaunching(aNotification: NSNotification) {

    if loggedIn {
        self.showViewController(NSStoryboard.mainViewController())

    } else {
        let loginController = NSStoryboard.loginViewController()
        loginController.delegate = self
        self.showViewController(loginController)
    }
}

private func showViewController(viewController: NSViewController) {
    if let mainWindow = NSApplication.sharedApplication().mainWindow {
        mainWindow.contentViewController = viewController

    } else {
        print("Error: No main window!")
    }
}

About half of the times the window is empty and I see in the console "Error: No main window!". I thought maybe I can use applicationDidBecomeActive but this is called basically when it comes to the foreground and this is not what I need.

Further, the times when it works, and I log in, then I want to show the main view controller:

func onLoginSuccess() {
    self.showViewController(NSStoryboard.mainViewController())
}

And here I also get "Error: No main window!" (always) and nothing happens.

The docs say following about mainWindow being nil:

The value in this property is nil when the app’s storyboard or nib file has not yet finished loading. It might also be nil when the app is inactive or hidden.

But why is the storyboard not finished loading or the app inactive when I'm launching it? And on login success the app is definitely active and in the foreground and the main window is always nil.

What am I doing wrong? How can I implement this workflow? Alternatively I could create a "parent" view controller, have that one connected to the window in the storyboard, and add the login or main view controller as nested view controllers to that. But don't really like having to add a do nothing view controller.

I'm using XCode 7(beta 4), Swift 2, OSX 10.10.4

Edit:

The NSStoryboard methods come from an extension, it looks like this:

extension NSStoryboard {

    private class func mainStoryboard() -> NSStoryboard { return NSStoryboard(name: "Main", bundle: NSBundle.mainBundle()) }
    private class func signupStoryboard() -> NSStoryboard { return NSStoryboard(name: "LoginRegister", bundle: NSBundle.mainBundle()) }

    class func mainViewController() -> ViewController {
        return self.mainStoryboard().instantiateControllerWithIdentifier("MainViewController") as! ViewController
    }

    class func loginViewController() -> LoginViewController {
        return self.signupStoryboard().instantiateControllerWithIdentifier("LoginViewController") as! LoginViewController
    }

    class func registerViewController() -> RegisterViewController {
        return self.signupStoryboard().instantiateControllerWithIdentifier("RegisterViewController") as! RegisterViewController
    }
}
like image 761
User Avatar asked Aug 11 '15 19:08

User


1 Answers

To put the solution we found in the comments as an answer:

Apparently NSApplication.sharedApplication().mainWindow is a different window than my main window in the storyboard.

So, I created an NSWindowController subclass and assigned it to the window in the storyboard, using the identity inspector.

Then I moved the logic I had in app delegate to this NSWindowController. It looks like this:

class MainWindowController: NSWindowController, LoginDelegate {

    override func windowDidLoad() {

        if loggedIn {
            self.onLoggedIn()
        } else {
            let loginController = NSStoryboard.loginViewController()
            loginController.delegate = self
            self.contentViewController = loginController
        }
    }

    func onLoggedIn() {
        self.contentViewController = NSStoryboard.mainViewController()
    }

    func onLoginSuccess() {
        self.onLoggedIn()
    }
}

* Thanks Lucas Derraugh for pointing me in the right direction!

like image 54
User Avatar answered Oct 01 '22 13:10

User