I am making a macOS Cocoa application which only runs in the menu bar. When I initially created the project, Xcode gave me a file called MainMenu.xib. This MainMenu.xib file does not appear to contain anything relevant to my menu bar application, so I wish to remove it.
The Cocoa entry point, the function NSApplicationMain, "loads the main nib file from the application’s main bundle". I read elsewhere that Cocoa finds "the main nib file" by consulting the key NSMainNibFile in my Info.plist, which was set to the string MainMenu. I deleted the key NSMainNibFile, and my program still behaved the same. From this, I assumed that Cocoa saw the absence of this key, and so it skipped its nib/xib loading step.
Since my MainMenu.xib file was no longer referenced from anywhere, I deleted it (which deleted some innocent-looking references from my project.pbxproj). However, after deleting MainMenu.xib, my application no longer works. The applicationDidFinishLaunching method on my AppDelegate class is not called!
This means two things. First, this means Cocoa magically still finds my MainMenu.xib file even if NSMainNibFile is not present (and Cocoa still finds the file if I rename it to Foo.xib). More importantly, this means means that something in my MainMenu.xib is still required for my application to run. Here is the complete MainMenu.xib:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Foo" customModuleProvider="target"/>
</objects>
</document>
I think the problem is that my MainMenu.xib refers to my AppDelegate class, and Cocoa uses this in order to instantiate the AppDelegate class, and then call applicationDidFinishLaunching on the object. This is confusing, because I thought the @NSApplicationMain annotation on my AppDelegate class was sufficient.
I have a few questions as a result of this:
- How is Cocoa (i.e.
NSApplicationMain) finding myMainMenu.xibfile? What is Cocoa's search procedure? How do I tell Cocoa to skip this loading step? - What is my
MainMenu.xibfile doing? That is, how does Cocoa interpret theMainMenu.xibfile, and what does it do as a result? Specifically, how does this file result in myAppDelegateclass getting instantiated? - How do I recreate this logic purely programmatically in Swift 3, so that I can delete the
MainMenu.xibfile? What are the APIs I need to use?