I would like to use a custom subclass of NSApplication
to create the application instance of my program. The object retrieved by NSApplication.shared
or NSApp
should be an instance of the Application
class below:
class Application: NSApplication {
// My own methods
}
I first tried to set Principal class in Info.plist
from NSApplication
to Application
but I later learned I had to use $(PRODUCT_MODULE_NAME).Application
instead. This worked, and instantiated my subclass as expected, when I tried in a fresh macOS Application template with no modifications other than changing the Principal class and adding the code to define my subclass.
The issue is that the above changes had no effect whatsoever in an existing application project with a different structure.
To reproduce this in the fresh project, I removed the .xib
/.storyboard
file, and replaced the AppDelegate.swift
file with only a main.swift
file containing the following:
import Cocoa
class Application: NSApplication, NSApplicationDelegate {
func applicationShouldTerminateAfterLastWindowClosed(_ _: NSApplication) -> Bool {
return true
}
}
NSApplication.shared.delegate = (NSApp as! Application)
NSApp.run()
In this case, the as!
downcast will fail, meaning that the application object created by NSApplication.shared
is not an instance of my custom class, even though I set the Principal class to the same string that worked before. Removing Info.plist
entirely seems to have no effect at all.
I suspect that the other project structure comprising a delegate annotated with @NSApplicationMain
somehow registers the value of Principal class in Info.plist
to be used to instantiate the application instance, but using NSApplication.shared
to manually initialize the application does not include that step.
How can I use a custom class for my application object in this particular case where I use NSApplication.shared
directly?
In case this matters my macOS version is 10.15.7 and my Swift version is 5.3.2.
The solution is to access the shared
property though the subclass I want to instantiate. This means using Application.shared
instead of NSApplication.shared
. The code responsible for loading the Principal class is not in the shared
method and is not automatically invoked before the entry point of the program.
print(Application.shared is Application) // Prints true
NSApp.run()