是否有一个 main.swift 相当于 @NSApplicationMain 注释?
Is there a main.swift which is equivalent to the @NSApplicationMain annotation?
在 XCode 中创建一个新的 Cocoa 项目给我一个 AppDelegate.swift
文件,如下所示:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
}
The @NSApplicationMain
attribute is documented here 为
NSApplicationMain
Apply this attribute to a class to indicate that it is the application delegate. Using this attribute is equivalent to calling the NSApplicationMain(_:_:)
function.
If you do not use this attribute, supply a main.swift
file with code at the top level that calls the NSApplicationMain(_:_:)
function as follows:
import AppKit
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
文档中的说明不起作用:AppDelegate
class 从未实例化。在 , vadian 中建议 main.swift
的以下内容比文档中的代码更好:
import Cocoa
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
但是,这仍然没有提供与 @NSApplicationMain
相同的行为。考虑将上述 main.swift
与以下 AppDelegate.swift
:
结合使用
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var foo: NSStatusBar! = NSStatusBar.system();
}
上面的 AppDelegate.swift
使用 @NSApplicationMain
注释,但是当使用上面的 main.swift
时,它在运行时失败并出现错误
Assertion failed: (CGAtomicGet(&is_initialized)), function CGSConnectionByID, file Services/Connection/CGSConnection.c, line 127.
我认为这个 is_initialized
错误意味着 @NSApplicationMain
设置了一些东西,以便 AppDelegate
在 一些初始化之后实例化 =19=]函数。这表明以下 main.swift
,它将委托初始化移动到 NSApplicationMain
调用之后:
import Cocoa
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
但是,这 也行不通 ,因为 NSApplicationMain
永远不会 returns!上面的 main.swift
相当于文档中的 broken suggestion,因为后两行是死代码。
因此我认为必须有一些方法可以将对我的 AppDelegate
class 的引用作为参数传递给 NSApplicationMain
函数,这样 Cocoa 就可以做到它的初始化,然后实例化我的 AppDelegate
class 本身。但是,我看不出有什么办法。
是否有 main.swift
提供真正等同于 @NSApplicationMain
注释的行为?如果是这样,那 main.swift
是什么样子的?如果不是,@NSApplicationMain
实际上在做什么,我该如何修改它?
文档假设有一个 xib 或故事板通过 Interface Builder 中的对象(蓝色立方体)实例化 AppDelegate
class。在这种情况下
main.swift
包含NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
和
@NSApplicationMain
在AppDelegate
class
行为完全相同。
如果没有 xib 或故事板,您负责初始化 AppDelegate
class,将其分配给 NSApplication.shared.delegate
和 运行 应用程序。您还必须考虑对象的出现顺序。例如,您无法在调用 NSApplication.shared
启动应用程序之前初始化与 AppKit
相关的对象。
例如,语法略有变化
let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
你可以在applicationDidFinishLaunching
之外的AppDelegate
初始化状态栏:
let statusItem = NSStatusBar.system().statusItem(withLength: -1)
因为 NSApplication.shared()
调用 在 初始化 AppDelegate
class.
之前启动应用程序
将默认 Cocoa 项目的 AppDelegate.swift
替换为以下 main.swift
。该应用程序的行为将与以前相同。因此,以下代码提供了 @NSApplicationMain
注释的语义。
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate { }
let myApp: NSApplication = NSApplication.shared()
let myDelegate: AppDelegate = AppDelegate()
myApp.delegate = myDelegate
let mainBundle: Bundle = Bundle.main
let mainNibFileBaseName: String = mainBundle.infoDictionary!["NSMainNibFile"] as! String
mainBundle.loadNibNamed(mainNibFileBaseName, owner: myApp, topLevelObjects: nil)
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
(我在 的帮助下构建了这个。如果上面的行为与默认的 Cocoa 项目应用程序之间存在任何差异,请告诉我。)
这是我为了 运行 没有 @NSApplicationMain
注释和函数 NSApplicationMain(_, _)
的应用程序所做的,同时使用由 Xcode 生成的初始 NSWindowController
的 Storyboard应用程序模板(与下面描述的 Main Menu
相关的稍作修改)。
文件: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
}
}
文件 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()
关于 MainMenu.xib
文件的注释:
Xcode 应用程序模板使用 Application Scene
创建故事板,其中包含 Main Menu
。目前似乎没有办法以编程方式从 Application Scene
加载 Main Menu
。但是有 Xcode 文件模板 Main Menu
,它创建 MainMenu.xib
文件,我们可以通过编程方式加载它。
在 XCode 中创建一个新的 Cocoa 项目给我一个 AppDelegate.swift
文件,如下所示:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
}
The @NSApplicationMain
attribute is documented here 为
NSApplicationMain
Apply this attribute to a class to indicate that it is the application delegate. Using this attribute is equivalent to calling the
NSApplicationMain(_:_:)
function.If you do not use this attribute, supply a
main.swift
file with code at the top level that calls theNSApplicationMain(_:_:)
function as follows:import AppKit NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
文档中的说明不起作用:AppDelegate
class 从未实例化。在 main.swift
的以下内容比文档中的代码更好:
import Cocoa
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
但是,这仍然没有提供与 @NSApplicationMain
相同的行为。考虑将上述 main.swift
与以下 AppDelegate.swift
:
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var foo: NSStatusBar! = NSStatusBar.system();
}
上面的 AppDelegate.swift
使用 @NSApplicationMain
注释,但是当使用上面的 main.swift
时,它在运行时失败并出现错误
Assertion failed: (CGAtomicGet(&is_initialized)), function CGSConnectionByID, file Services/Connection/CGSConnection.c, line 127.
我认为这个 is_initialized
错误意味着 @NSApplicationMain
设置了一些东西,以便 AppDelegate
在 一些初始化之后实例化 =19=]函数。这表明以下 main.swift
,它将委托初始化移动到 NSApplicationMain
调用之后:
import Cocoa
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
但是,这 也行不通 ,因为 NSApplicationMain
永远不会 returns!上面的 main.swift
相当于文档中的 broken suggestion,因为后两行是死代码。
因此我认为必须有一些方法可以将对我的 AppDelegate
class 的引用作为参数传递给 NSApplicationMain
函数,这样 Cocoa 就可以做到它的初始化,然后实例化我的 AppDelegate
class 本身。但是,我看不出有什么办法。
是否有 main.swift
提供真正等同于 @NSApplicationMain
注释的行为?如果是这样,那 main.swift
是什么样子的?如果不是,@NSApplicationMain
实际上在做什么,我该如何修改它?
文档假设有一个 xib 或故事板通过 Interface Builder 中的对象(蓝色立方体)实例化 AppDelegate
class。在这种情况下
main.swift
包含NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
和
@NSApplicationMain
在AppDelegate
class
行为完全相同。
如果没有 xib 或故事板,您负责初始化 AppDelegate
class,将其分配给 NSApplication.shared.delegate
和 运行 应用程序。您还必须考虑对象的出现顺序。例如,您无法在调用 NSApplication.shared
启动应用程序之前初始化与 AppKit
相关的对象。
例如,语法略有变化
let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
你可以在applicationDidFinishLaunching
之外的AppDelegate
初始化状态栏:
let statusItem = NSStatusBar.system().statusItem(withLength: -1)
因为 NSApplication.shared()
调用 在 初始化 AppDelegate
class.
将默认 Cocoa 项目的 AppDelegate.swift
替换为以下 main.swift
。该应用程序的行为将与以前相同。因此,以下代码提供了 @NSApplicationMain
注释的语义。
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate { }
let myApp: NSApplication = NSApplication.shared()
let myDelegate: AppDelegate = AppDelegate()
myApp.delegate = myDelegate
let mainBundle: Bundle = Bundle.main
let mainNibFileBaseName: String = mainBundle.infoDictionary!["NSMainNibFile"] as! String
mainBundle.loadNibNamed(mainNibFileBaseName, owner: myApp, topLevelObjects: nil)
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
(我在
这是我为了 运行 没有 @NSApplicationMain
注释和函数 NSApplicationMain(_, _)
的应用程序所做的,同时使用由 Xcode 生成的初始 NSWindowController
的 Storyboard应用程序模板(与下面描述的 Main Menu
相关的稍作修改)。
文件: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
}
}
文件 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()
关于 MainMenu.xib
文件的注释:
Xcode 应用程序模板使用 Application Scene
创建故事板,其中包含 Main Menu
。目前似乎没有办法以编程方式从 Application Scene
加载 Main Menu
。但是有 Xcode 文件模板 Main Menu
,它创建 MainMenu.xib
文件,我们可以通过编程方式加载它。