App Store Guideline 4.0: Reopen a Closed Mac App Window
Content edited . This editorial update does not represent a new runtime test.
On this page
This Guideline 4.0 Design case concerns a Mac app that stays running after its main window closes but offers no way to reopen it. Choose an explicit window policy: quit after the last window closes, or keep running and provide both a menu action and Dock reopening behavior. This fixes this particular lifecycle problem; it does not address every Design rejection.

Reproduce before changing the lifecycle
- Launch the submitted version and open its main window.
- Close it with the red close button, without choosing Quit.
- Check whether the process and app menu remain active.
- Click the Dock icon and look for a Window or equivalent menu action. Record which action fails to restore the interface.
The historical note described a missing menu item. The image above is an illustration, not an original reviewer screenshot. No original review transcript or new acceptance receipt was available for this revision.
Option 1: Quit after the last window closes
For an app that should exit completely, add this method to its actual NSApplicationDelegate:
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
A standalone function does not register a delegate. Before choosing this policy, check unsaved documents, background work and any menu-bar functionality. Apple documents the termination callback.
Option 2: Reuse one AppKit window controller
The following delegate example is for a single-window, non-document AppKit app. Add its methods to the existing delegate rather than introducing a second application lifecycle. Set that delegate in your app’s existing startup configuration. The example constructs a blank window; replace its content with the product interface.
import AppKit
@MainActor
final class AppDelegate: NSObject, NSApplicationDelegate {
private lazy var mainWindowController: NSWindowController = {
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 640, height: 480),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false
)
window.title = "Main Window"
window.isReleasedWhenClosed = false
window.center()
return NSWindowController(window: window)
}()
func applicationDidFinishLaunching(_ notification: Notification) {
// In an existing app, add this item to its existing Window menu.
let menuBar = NSApp.mainMenu ?? NSMenu()
NSApp.mainMenu = menuBar
let windowMenu = NSApp.windowsMenu ?? NSMenu(title: "Window")
if NSApp.windowsMenu == nil {
let parent = NSMenuItem(title: "Window", action: nil, keyEquivalent: "")
parent.submenu = windowMenu
menuBar.addItem(parent)
NSApp.windowsMenu = windowMenu
}
let item = NSMenuItem(
title: "Show Main Window",
action: #selector(showMainWindow(_:)),
keyEquivalent: ""
)
item.target = self
windowMenu.addItem(item)
showMainWindow(nil)
}
@objc func showMainWindow(_ sender: Any?) {
mainWindowController.showWindow(sender)
if let window = mainWindowController.window {
if window.isMiniaturized { window.deminiaturize(sender) }
window.makeKeyAndOrderFront(sender)
}
NSApp.activate(ignoringOtherApps: true)
}
func applicationShouldHandleReopen(
_ sender: NSApplication, hasVisibleWindows: Bool
) -> Bool {
showMainWindow(nil)
return false // Handled here; skip AppKit's default reopen behavior.
}
func applicationShouldTerminateAfterLastWindowClosed(
_ sender: NSApplication
) -> Bool {
return false
}
}
The retained controller and lazy creation avoid constructing a new window on every action. The same action handles launch, menu selection and reopening, including a minimized window. Returning false from the reopen callback means this delegate handled the event. NSWindowController.showWindow is the controller entry point.
Do not paste this controller into a document-based app or a SwiftUI WindowGroup and also let that lifecycle create its windows. Use the existing document controllers or scene identity, and test whether repeated actions create duplicates. Keep the Quit command and existing menu items; this example only adds a window action.
Validate the submitted app, not just the snippet
- Close the main window, choose Window → Show Main Window, and verify its content returns.
- Close again and click the Dock icon. Repeat five times; the intended window count must stay one.
- Minimize the window and click the Dock icon. Confirm it becomes usable rather than remaining hidden.
- Test unsaved state and any background operation. Reopening must not silently discard work or start a duplicate task.
- Quit and relaunch. Repeat in the archived build used for submission, and record app version, macOS version and results in Review Notes.
Verification evidence for this editorial update (2026-10-14): both Swift examples passed xcrun swiftc -typecheck with Apple Swift 6.4 and the installed macOS SDK. No GUI app was launched; the close/menu/Dock sequence and App Store acceptance remain unverified. Compiler success checks API usage, not the behavior of your integrated app.
Use Apple’s Design guideline for the actual review scope. Related: ITMS-91053 and privacy manifests concern submission declarations rather than window lifecycle.