Learn more about Russian war crimes in Ukraine.

What is NSApplication? How is it instantiated? What is NSApp?

The core of a Cocoa application is the NSApplication class. The docs for it say

Every app must have exactly one instance of NSApplication (or a subclass of NSApplication). Your program’s main() function should create this instance by invoking the shared() class method.

This is a bit confusing to the beginning developer. I had never seen an NSApplication instance; I had never seen my main() function; and I had never invoked a shared() method. The main() function in Swift is created by the @NSApplicationMain annotation, by creating the file main.swift with the following contents:

import AppKit
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

This is doubly confusing, because this “main() function” does not invoke a shared() method on anything. The above docs are misleading; you are not required to call this shared() method, because NSApplicationMain(...) will do it for you, as it explains:

Creates the application, loads the main nib file from the application’s main bundle, and runs the application.

These docs are also a little confusing, because NSApplicationMain does not necessarily create the application object. You can do it yourself, in which case NSApplicationMain(...) will use the NSApplication instance you chose. The mechanism for this is the NSApp variable, which is explained further down:

The shared() method also initializes the global variable NSApp, which you use to retrieve the NSApplication instance. shared() only performs the initialization once; if you invoke it more than once, it simply returns the NSApplication object it created previously.

Here’s an example of initializing the NSApplication ourselves:

import AppKit
print("NSApp: \(NSApp)")
let myApp = NSApplication.shared()
print("NSApp: \(NSApp)")
print("myApp: \(myApp)")
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

This prints:

NSApp: nil
NSApp: Optional(<NSApplication: 0x600000101710>)
myApp: <NSApplication: 0x600000101710>

Notice that NSApp starts off as nil. NSApplication.shared() creates an object, then sets NSApp to point to it, and returns the object too. When NSApplicationMain is then called, the “Creates the application” effectively just calls NSApplication.shared() again, which returns the instance you created.

You can customize the behavior of NSApplication via standard subclassing. If you subclass NSApplication as MyApplication, then call MyApplication.shared() instead:

import AppKit
class MyApplication : NSApplication { }
let app: NSApplication = MyApplication.shared()
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

You might think that, if you neglect to call shared(), the NSApplicationMain(...) call defaults to NSApplication.shared(). This is not the case. Actually, NSApplicationMain uses the NSPrincipalClass key of your Info.plist to determine what class to call shared() on. We can emulate this behavior ourselves:

import AppKit
let principalClassName: String = Bundle.main.infoDictionary!["NSPrincipalClass"] as! String
let principalClass: NSApplication.Type = NSClassFromString(principalClassName)! as! NSApplication.Type
let app: NSApplication = principalClass.shared()
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

What can computers do? What are the limits of mathematics? And just how busy can a busy beaver be? This year, I’m writing Busy Beavers, a unique interactive book on computability theory. You and I will take a practical and modern approach to answering these questions — or at least learning why some questions are unanswerable!

It’s only $19, and you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

After months of secret toil, I and Andrew Carr released Everyday Data Science, a unique interactive online course! You’ll make the perfect glass of lemonade using Thompson sampling. You’ll lose weight with differential equations. And you might just qualify for the Olympics with a bit of statistics!

It’s $29, but you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

More by Jim

Tagged . All content copyright James Fisher 2017. This post is not associated with my employer. Found an error? Edit this page.