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.xib
file? What is Cocoa's search procedure? How do I tell Cocoa to skip this loading step? - What is my
MainMenu.xib
file doing? That is, how does Cocoa interpret theMainMenu.xib
file, and what does it do as a result? Specifically, how does this file result in myAppDelegate
class getting instantiated? - How do I recreate this logic purely programmatically in Swift 3, so that I can delete the
MainMenu.xib
file? What are the APIs I need to use?