【问题标题】:how to Load initial window controller from storyboard?如何从情节提要加载初始窗口控制器?
【发布时间】:2015-09-07 13:55:23
【问题描述】:

我经历了很多问题,但没有一个能回答我的问题。 我正在尝试以编程方式加载初始窗口 这是我所做的。

我添加了 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 是-

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()
    }



}

在 AppFlow 中,我正在尝试从情节提要加载窗口控制器。-

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

}

但我无法启动初始窗口控制器和视图控制器。应用程序自动启动和终止,不向用户显示任何窗口。

我做错了什么?感谢您的帮助。

【问题讨论】:

  • 你的方法有没有成功?

标签: macos swift cocoa storyboard


【解决方案1】:

这是我在没有属性@NSApplicationMain 和函数NSApplicationMain(_, _) 的情况下以编程方式从情节提要(以及MainMenu)加载初始窗口所做的工作

文件: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
   }
}

文件 ma​​in.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()

关于MainMenu.xib文件的注意事项:

Xcode 应用程序模板使用包含Main MenuApplication Scene 创建故事板。目前似乎没有办法以编程方式从Application Scene 加载Main Menu。但是有 Xcode 文件模板Main Menu,它创建了MainMenu.xib 文件,我们可以通过编程方式加载它。

【讨论】:

  • 我正在尝试让它与 Swift 5 一起使用。除了加载主菜单外,它似乎工作正常。 “无法加载 nibName: MainMenu 捆绑包 NSBundle”
  • 没关系...我终于完全理解了您在主菜单上的注释。我发现我需要先从 File->New->File 创建一个文件,然后选择“Main Menu”。
【解决方案2】:

这不是您启动(和维护)应用程序主运行循环的方式。见@NSApplicationMain。这会导致主运行循环被设置并运行,直到它被终止。不再需要 main.swift 文件,因为您可以直接将其放入应用代理的文件中。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!


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

}

Xcode 的新应用程序项目模板会为您完成这项工作。

【讨论】:

  • 感谢您的帮助。我只是想自己做所有这些事情来了解这个模板是如何工作的。我故意评论了@NSApplicationMain。
猜你喜欢
  • 1970-01-01
  • 2012-06-08
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-12
相关资源
最近更新 更多