"Reveal worked every time the app was already running. On a cold launch it silently did nothing."
Two Ways In
A SwiftUI app starts at a @main struct … : App; when it needs AppKit callbacks it attaches a delegate with @NSApplicationDelegateAdaptor. An AppKit-owned app starts at a @main type whose static func main() creates NSApplication.shared, installs a delegate, sets the activation policy and calls run(). Several family Mac apps start the second way, because it makes launch order explicit.
The activation policy decides how the app presents itself: .regular (Dock icon, menu bar, can be frontmost), .accessory (no Dock icon, can still show windows — the menu-bar utility shape), or .prohibited. Setting LSUIElement in Info.plist gives an app accessory behaviour from the first instant, before any code runs.
Launch Is a Race You Did Not Schedule
A file workbench accepts "reveal this file" requests from other programs through application(_:open:). It worked perfectly when the app was running, and did nothing on a cold launch. Two independent races were involved, and fixing only one left the bug:
- The open event can be delivered before
applicationDidFinishLaunchinghas built the window controller, so an optional-chained call on a controller that does not exist yet is a no-op. - Any asynchronous session restore that completes afterwards overwrites the revealed location with the restored one.
The fix parks every incoming URL and drains the queue only when both conditions hold: the controller exists and the restore has finished — and the restore must signal completion on its empty and error paths too, or a request waits forever. Test cold and warm launches separately; a warm pass proves nothing about launch ordering.
Ending Without Losing the Session
A terminal with native window tabs saved its tab layout whenever a window closed. On quit, applicationShouldTerminate runs while every window is still open; then the windows close one by one, each close saving a snapshot with one fewer window, and the last save wrote an empty session. The fix takes the snapshot in applicationShouldTerminate, sets a terminating flag, and turns later per-window saves into no-ops.
One more termination fact matters for fleet tooling: a document app must be quit politely (an Apple Event, or the Quit menu) rather than killed. applicationShouldTerminate — where unsaved documents are handled — never runs on SIGTERM.