swift 在应用程序启动时有条件地显示NSViewController

3lxsmp7m  于 2022-12-22  发布在  Swift
关注(0)|答案(2)|浏览(114)

我正在开发一个OSX应用程序,如果用户还没有登录,我会先显示一个登录/注册窗口。
登录成功后,我显示我的主视图控制器.
如果用户已经登录(存储令牌),则应用必须直接使用主视图控制器启动。
我是OSX开发的新手,我在谷歌上搜索了这种场景,但什么也没找到。
所以我提出了我认为应该起作用的方法。它有时起作用,有时我得到一个空白窗口。
在故事板中,我让主菜单和窗口控制器。我删除了"包含" segue到我的主视图控制器。
在AppDelegate中,我放置了以下内容:

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!")
    }
}

大约有一半的时间窗口是空的,我在控制台中看到"错误:没有主窗口!"。我想也许我可以使用applicationDidBecomeActive,但这基本上是在前台调用的,这不是我需要的。
此外,当它工作的时候,我登录,然后我想显示主视图控制器:

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

这里我还得到了"错误:没有主窗口!"(总是),什么也没有发生。
文件中说以下mainWindow为零:
当应用程序的情节提要或nib文件尚未完成加载时,此属性中的值为nil。当应用程序处于非活动或隐藏状态时,此属性中的值也可能为nil。
但是为什么故事板没有完成加载或者应用程序在我启动的时候是不活动的呢?而且在登录成功的时候,应用程序肯定是活动的,在前台,主窗口总是空的。
我做错了什么?我怎样才能实现这个工作流?或者我可以创建一个"父"视图控制器,将它连接到故事板中的窗口,然后将登录或主视图控制器作为嵌套视图控制器添加到其中。但我真的不喜欢添加一个什么都不做的视图控制器。
我使用的是XCode 7(beta 4)、Swift 2和OSX 10.10.4
编辑:
NSStoryboard方法来自一个扩展,如下所示:

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
    }
}
wj8zmpe1

wj8zmpe11#

把我们在评论中找到的解决方案作为答案:
显然,NSApplication.sharedApplication().mainWindow是一个与我在故事板中的主窗口不同的窗口。
因此,我创建了一个NSWindowController子类,并使用identity inspector将其分配给故事板中的窗口。
然后我将应用委托中的逻辑移到了这个NSWindowController中,它看起来像这样:

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()
    }
}
  • 谢谢卢卡斯·德劳给我指出了正确的方向!
3zwjbxry

3zwjbxry2#

enum Storyboards: String {
case main = "Main"
case settings = "Settings"

func instantiateVC<T>(_ identifier: T.Type) -> T?  {
    let storyboard = NSStoryboard(name: rawValue, bundle: nil)
    guard let viewcontroller = storyboard.instantiateController(withIdentifier: String(describing: identifier)) as? T else { return nil}
    return viewcontroller
  }
}

 //Need to use like this
 //Make sure Storyboard Id and class-name are the same

 if let windowController = Storyboards.main.instantiateVC(IDMainController.self) {
     windowController.showWindow(nil) 
    //----- OR -----
    self.contentViewController = windowController
 } else {
    print("Cannot find IDMainController")
}

相关问题