Creating a new Cocoa project in XCode gives me an AppDelegate.swift file which looks like this:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
}
The @NSApplicationMain attribute is documented here as
NSApplicationMainApply 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.swiftfile with code at the top level that calls theNSApplicationMain(_:_:)function as follows:import AppKit NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
The instructions in the documentation do not work: the AppDelegate class is never instantiated. In this answer, vadian suggests the following contents for main.swift, which work better than the code in the documentation:
import Cocoa
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
However, this still does not provide the same behavior as @NSApplicationMain. Consider using the above main.swift with the following AppDelegate.swift:
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var foo: NSStatusBar! = NSStatusBar.system();
}
The above AppDelegate.swift works with an @NSApplicationMain annotation, but when using the above main.swift, it fails at runtime with the error
Assertion failed: (CGAtomicGet(&is_initialized)), function CGSConnectionByID, file Services/Connection/CGSConnection.c, line 127.
I think this is_initialized error means that @NSApplicationMain sets things up so that the AppDelegate is instantiated after some initialization by the NSApplicationMain function. This suggests the following main.swift, which moves the delegate initialization to after the NSApplicationMain call:
import Cocoa
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
let appDelegate = AppDelegate()
NSApplication.shared().delegate = appDelegate
However, this doesn't work either, because NSApplicationMain never returns! The above main.swift is equivalent to the broken suggestion in the documentation, because the latter two lines are dead code.
I therefore think there must be some way to pass a reference to my AppDelegate class as an argument to the NSApplicationMain function, so that Cocoa can do its initialization and then instantiate my AppDelegate class itself. However, I see no way to do this.
Is there a main.swift which provides behavior which is truly equivalent to the @NSApplicationMain annotation? If so, what does that main.swift look like? If not, what is @NSApplicationMain actually doing, and how do I modify it?