What does a Mac app need that an iOS app does not: the menu bar, windows, the App Sandbox, Hardened Runtime and notarization?

20.3.2 · L3 · Interview

Predict first

An AppKit menu with a Quit item and a separator, and a window created but not shown. What do they report?

import AppKit

let m = NSMenu(title: "Main")
let item = NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
m.addItem(item)
m.addItem(.separator())
print(m.items.count, item.keyEquivalent, item.keyEquivalentModifierMask == .command, m.items[1].isSeparatorItem)
let w = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300), styleMask: [.titled, .closable, .resizable], backing: .buffered, defer: true)
print(w.styleMask.contains(.resizable), w.frame.width, w.isVisible)
  • 2 q true true, then true 400.0 false
  • 1 q false false, then false 400.0 true
  • 2 Q true true, then true 300.0 false

Mental model. The menu bar is the building’s central directory that always lists what the occupant can do. The sandbox is a lease that says which rooms the tenant may enter (optional if you rent outside the store), and notarization is the building inspector’s stamp that lets visitors trust the door.

A Mac app is expected to follow Mac conventions. The menu bar is the app’s command surface: an NSMenu of NSMenuItems, each with a title, an action sent down the responder chain (to the first responder, the window controller, the app delegate), and a key equivalent whose default modifier is Command (so a “Quit” item with key equivalent q triggers on ⌘Q). Standard items (About, Settings, Hide, Quit, Edit’s Undo and Paste, Window’s Minimize) must exist and work; in SwiftUI declare them with .commands { CommandGroup … } and keyboard shortcuts with .keyboardShortcut. Windows are real: resizable, with minimum sizes, a title bar and toolbar, full-screen, tabs, multiple windows per document and per-window state restoration; an NSWindow has a style mask (.titled, .closable, .resizable, .fullSizeContentView) and a frame, and is not visible until ordered front, and a command-line process has an activation policy that keeps it out of the Dock. Apps run for a long time, can be launched at login (SMAppService), live in the menu bar (MenuBarExtra), handle Services, drag and drop, the Touch Bar and shortcuts, and respond to system appearance, accent colour and accessibility settings.

The App Sandbox is the Mac’s counterpart to the iOS sandbox, but opt-in outside the Mac App Store: with the com.apple.security.app-sandbox entitlement the app can only access its own container plus what you request with entitlements (network client and server, camera, microphone, user-selected files com.apple.security.files.user-selected.read-write, downloads, USB, printing). Access to files the user picks persists through security-scoped bookmarks (a sandboxed app that wants to reopen a folder next launch stores a bookmark and calls startAccessingSecurityScopedResource()), and the home directory is the container, so a path under /Users may not be the real home. Mac App Store apps must be sandboxed; direct-distribution apps may skip it but must use the Hardened Runtime (code-signing protections against injection, with explicit exception entitlements for JIT, loading unsigned libraries or the like) and be notarized (uploaded to Apple’s notary service, which scans for malware and issues a ticket that you staple, so Gatekeeper lets users open the app). Other differences from iOS: update mechanisms outside the store (Sparkle or a custom updater) need signing, helper tools and launch agents install through SMAppService, system extensions have their own approval flow, permissions (TCC prompts for files, screen recording, accessibility, full disk access) are per-app and revocable in System Settings, and crash and energy diagnostics use Console and Instruments on the Mac. Plan the signing and distribution path early, because it shapes capabilities.

The menu has two items, the key equivalent is a plain q with the default Command modifier, the second item is a separator, and a new window is sized but not visible until ordered front.

Common traps

  • Shipping a Mac app with a missing or non-working standard menu item. Users expect ⌘Q, ⌘W, ⌘, and Edit commands; wire them to the responder chain.
  • Skipping notarization for direct distribution. Gatekeeper blocks the app for users; sign with a Developer ID and notarize.

They might follow up with

  • What is the default modifier of a menu item’s key equivalent? Command.
  • How does a sandboxed app reopen a user-chosen folder later? A security-scoped bookmark and startAccessingSecurityScopedResource().

Related questions

  • 20.3.1 Mac Catalyst, native AppKit, SwiftUI for macOS, or an iPad app on the Mac: how do you choose, and what…
  • 20.1.2 How do the platforms differ in input, process model and capabilities, and which entitlements and APIs change…
  • 6.8.2 How do keychain access groups differ from app groups?

← Mac Catalyst, native AppKit, SwiftUI for macOS, or an iPad app on the…