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