how to Load initial window controller from storyboard?

拜拜、爱过 提交于 2020-06-12 07:29:42

问题


I have gone through many questoions but none of them snaswers my query. I am trying to load initial window programmatically Here is what I have done.

I have added main.swift as-

import Cocoa

private func runApplication(
    application: NSApplication         = NSApplication.sharedApplication(),
    delegate: NSApplicationDelegate?   = AppDelegate(),
    bundle: NSBundle                   = NSBundle.mainBundle(),
    nibName: String                    = "MainMenu",
    var topLevelObjects: NSArray?      = nil) {
        setApplicationDelegate(application, delegate)
}

private func setApplicationDelegate(application: NSApplication, delegate: NSApplicationDelegate?) -> NSApplication {
    if let delegate = delegate {
        application.delegate = delegate
    }
    return application
}

runApplication()

Appdelegate.swift is-

import Cocoa

//@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    var appControl:AppFlow?
    func applicationDidFinishLaunching(aNotification: NSNotification) {

    }

    func applicationWillTerminate(aNotification: NSNotification) {
        // Insert code here to tear down your application
    }
    override init() {
        //
        self.appControl = AppFlow()
        super.init()
    }



}

And in AppFlow I am trying to load window controller from storyboard.-

import Cocoa

class AppFlow{
    let initialStoryBoard:NSStoryboard?
    override init() {
        self.initialStoryBoard = NSStoryboard(name: "Main" , bundle : nil)
        super.init()
        var windowController = (self.initialStoryBoard?.instantiateControllerWithIdentifier("mainWindow")) as! NSWindowController
        windowController.window?.makeKeyAndOrderFront(nil)     
    }

}

But I am not able to launch initial window controller and view controller. App starts and terminates automatically, no window is presented to user.

What I am doing wrong? Thanks for your help.


回答1:


Here is what I did in order to load initial window from storyboard (as well as MainMenu) programmatically without attribute @NSApplicationMain and function NSApplicationMain(_, _)

File: AppConfig.swift (Swift 4)

struct AppConfig {

   static var applicationClass: NSApplication.Type {
      guard let principalClassName = Bundle.main.infoDictionary?["NSPrincipalClass"] as? String else {
         fatalError("Seems like `NSPrincipalClass` is missed in `Info.plist` file.")
      }
      guard let principalClass = NSClassFromString(principalClassName) as? NSApplication.Type else {
         fatalError("Unable to create `NSApplication` class for `\(principalClassName)`")
      }
      return principalClass
   }

   static var mainStoryboard: NSStoryboard {
      guard let mainStoryboardName = Bundle.main.infoDictionary?["NSMainStoryboardFile"] as? String else {
         fatalError("Seems like `NSMainStoryboardFile` is missed in `Info.plist` file.")
      }

      let storyboard = NSStoryboard(name: NSStoryboard.Name(mainStoryboardName), bundle: Bundle.main)
      return storyboard
   }

   static var mainMenu: NSNib {
      guard let nib = NSNib(nibNamed: NSNib.Name("MainMenu"), bundle: Bundle.main) else {
         fatalError("Resource `MainMenu.xib` is not found in the bundle `\(Bundle.main.bundlePath)`")
      }
      return nib
   }

   static var mainWindowController: NSWindowController {
      guard let wc = mainStoryboard.instantiateInitialController() as? NSWindowController else {
         fatalError("Initial controller is not `NSWindowController` in storyboard `\(mainStoryboard)`")
      }
      return wc
   }
}

File main.swift (Swift 4)

// Making NSApplication instance from `NSPrincipalClass` defined in `Info.plist`
let app = AppConfig.applicationClass.shared

// Configuring application as a regular (appearing in Dock and possibly having UI)
app.setActivationPolicy(.regular)

// Loading application menu from `MainMenu.xib` file.
// This will also assign property `NSApplication.mainMenu`.
AppConfig.mainMenu.instantiate(withOwner: app, topLevelObjects: nil)

// Loading initial window controller from `NSMainStoryboardFile` defined in `Info.plist`.
// Initial window accessible via property NSWindowController.window
let windowController = AppConfig.mainWindowController
windowController.window?.makeKeyAndOrderFront(nil)

app.activate(ignoringOtherApps: true)
app.run()

Note regarding MainMenu.xib file:

Xcode application template creates storyboard with Application Scene which contains Main Menu. At the moment seems there is no way programmatically load Main Menu from Application Scene. But there is Xcode file template Main Menu, which creates MainMenu.xib file, which we can load programmatically.




回答2:


This is not how you start (and maintain) an application's main run loop. See @NSApplicationMain. This causes the main run loop to be set up and run until it's terminated. There's no need for a main.swift file any longer, as you can just put this into your app delegate's file directly.

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!


    func applicationDidFinishLaunching(aNotification: NSNotification) {
        // Insert code here to initialize your application
    }

}

Xcode's new application project template does this for you.



来源:https://stackoverflow.com/questions/30974454/how-to-load-initial-window-controller-from-storyboard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!