NSApplication 是 macOS 应用程序的核心对象,代表整个正在运行的 App 实例。
它属于 AppKit 框架,用于管理 macOS App 的生命周期、事件分发、窗口管理、菜单控制等核心功能。
例如,在commands菜单中,添加NSApp.orderFrontStandardAboutPanel()方法:
CommandMenu("关于") {
Button("关于 ImageSlim") {
NSApp.orderFrontStandardAboutPanel()
}
}
在点击按钮后,调用NSApplication的orderFrontStandardAboutPanel方法,并弹出应用程序的相关信息。

基本用法
一、基础方法(生命周期与事件)
1、NSApp / NSApplication.shared:获取当前 App 实例(单例)。
let NSApp = NSApplication.shared
2、run():启动应用主事件循环(通常自动调用)。
NSApp.run()
启动主事件循环(Run Loop)。
通常不需要手动调用,会在 App 启动时由系统自动调用。
只有在完全手动控制 NSApplication 生命周期(如命令行工具包装成 GUI)时才用到。
3、terminate(_:):退出应用。
NSApp.terminate(nil)
请求终止应用(用户点击菜单“退出应用”时也会触发)。
实际退出前,会先调用 applicationShouldTerminate(_:) → applicationWillTerminate(_:)。
4、stop(_:):停止主事件循环。
NSApp.stop(nil)
停止主事件循环,相当于“暂停” App,但不等于退出。
通常用于嵌入式 GUI 工具或调试工具场景。
与 run() 成对使用。
5、reply(toApplicationShouldTerminate:):响应是否允许终止。
NSApp.reply(toApplicationShouldTerminate: true) // or false
用于异步终止确认,例如在 applicationShouldTerminate(_:) 返回 .terminateLater 时,执行保存操作后用它回复是否允许退出。
例如:
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
saveDataAsync {
NSApp.reply(toApplicationShouldTerminate: true)
}
return .terminateLater
}
saveDataAsync { … }:假设是自定义的函数,异步保存数据(比如保存文件、Core Data、云同步等)。
{ NSApp.reply(…) }:在保存完成后告诉系统:“我已经完成处理,现在可以退出”
6、sendEvent(_:):事件分发入口(如鼠标、键盘等)。
override func sendEvent(_ event: NSEvent) {
super.sendEvent(event)
// 自定义事件处理逻辑(如截屏、全局快捷键等)
}
用于拦截和扩展所有事件(键盘、鼠标、触控板等)。
常在 NSApplication 子类中重写,来添加全局快捷键支持、日志记录等。
7、nextEvent(matching:):获取下一个事件。
let event = NSApp.nextEvent(matching: .any, until: nil, inMode: .default, dequeue: true)
获取下一个事件。
用于自定义事件处理循环(很少手动使用,除非你要实现完全自定义的事件机制)。
通常用于 Kiosk 模式、全屏游戏、命令行嵌套 GUI 工具等极端场景。
二、App 状态相关
1、isActive:App 是否当前激活(在前台)。
NSApp.isActive
表示 App 是否在前台。
如果用户当前正在使用该 App(窗口处于最前),返回 true。
适合用于:控制播放、暂停、停止刷新、自动退出登录等行为。
2、isRunning:App 是否正在运行。
NSApp.isRunning
表示 App 是否已进入运行状态。
一般在 App 启动完成后始终为 true。
很少需要显式判断这个属性,主要用于低层调试或特殊工具类。
3、isHidden:是否被隐藏。
NSApp.isHidden
判断 App 是否被用户通过 ⌘H(Command+H)或菜单手动隐藏。
true 表示当前 App 窗口隐藏,但进程仍运行。
可以配合 NSWorkspace.shared.notificationCenter 监听隐藏/显示事件。
4、activationPolicy:App 的激活策略(如 .regular, .accessory, .prohibited)。
if NSApp.activationPolicy == .accessory {
print("这是一个菜单栏辅助工具 App")
}
表示 App 的“激活策略”,影响它是否能显示 Dock 图标、菜单栏等。
常用于工具类 App、菜单栏 App、后台服务 App等场景。
可选值(NSApplication.ActivationPolicy):
1、.regular:默认值,正常 App,显示 Dock 图标和菜单栏。
2、.accessory:辅助 App,无 Dock 图标、无菜单栏(菜单栏可自建)。
3、.prohibited:后台 App,不参与前台显示(如守护进程)。
可动态设置 activationPolicy,但通常需配合 activate(ignoringOtherApps:) 使用才能生效。
也可以在App启动时,设置激活策略:
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
NSApp.setActivationPolicy(.accessory) // 设置为辅助App
}
}
@main
struct ImageSlimApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
如果想要右上角弹出菜单栏,则需要手动添加NSStatusBar的菜单项。
5、windows:当前所有窗口。
let allWindows = NSApp.windows
当前 App 所有窗口的数组(包括隐藏、非主窗口等)。
可遍历所有窗口进行控制,如批量关闭、最小化等。
6、mainWindow / keyWindow:主窗口 / 焦点窗口。
NSApp.mainWindow
NSApp.keyWindow
mainWindow:用户操作的主窗口(点击时变主),通常是主 UI 窗口。
keyWindow:当前键盘事件聚焦的窗口(可能是弹窗)。
它们常用于获取当前焦点窗口、判断窗口类型、展示弹窗等场景。
三、用户交互控制
1、hide(_:):隐藏 App。
NSApp.hide(nil)
相当于用户按下 ⌘H。
会让 App 所有窗口全部隐藏,但进程仍在后台运行。
2、unhide(_:):显示 App。
NSApp.unhide(nil)
重新显示通过 hide(_:) 隐藏的所有窗口。
常与 activate(…) 搭配使用。
3、activate(ignoringOtherApps:):激活 App(让它跳到最前面)。
NSApp.activate(ignoringOtherApps: true)
让当前 App 进入前台,成为活动应用。
ignoringOtherApps: true 表示强制抢占焦点。
4、requestUserAttention(_:):请求用户注意(如在 Dock 上跳动)。
NSApp.requestUserAttention(.criticalRequest) // 或 .informationalRequest
只有App 未处于前台时,让 Dock 图标“跳动”以吸引用户。如果 App 处于前台时,Dock 图标不会“跳动”。
.criticalRequest 跳得更明显。
5、orderFrontStandardAboutPanel(_:):显示标准「关于本应用」面板。
NSApp.orderFrontStandardAboutPanel(nil)
macOS 自动生成的关于窗口(包含 App 名称、版本号、版权等信息)
信息来源于 Info.plist 的:CFBundleName、CFBundleShortVersionString、NSHumanReadableCopyright。
可以自定义内容:
NSApp.orderFrontStandardAboutPanel(options: [
NSApplication.AboutPanelOptionKey.credits: NSAttributedString(string: "开发者:方君宇"),
NSApplication.AboutPanelOptionKey.applicationVersion: "1.0.0",
])
6、orderFrontPreferencesPanel(_:):显示偏好设置(需手动实现)。
NSApp.orderFrontPreferencesPanel(nil)
只是一个“入口”,系统本身不会自动生成 UI。
需要手动将某个设置窗口打开。
可以在 Menu 中绑定此方法,然后实现它:
extension AppDelegate {
@objc func orderFrontPreferencesPanel(_ sender: Any?) {
preferencesWindow.makeKeyAndOrderFront(nil)
}
}
四、菜单栏相关
1、mainMenu:顶部菜单栏。
NSApp.mainMenu
表示 App 顶部菜单栏(整个 ⌘ 菜单)。
可以获取或设置整个菜单栏结构。
可以配合NSMenu设置菜单栏。
2、servicesMenu:系统服务子菜单。
NSApp.servicesMenu
指向 App 的 “服务” 菜单(通常在“App名称”菜单中)。
服务菜单会显示 macOS 的通用服务(如“打开URL”、“新建邮件”等)。
如果不设置它,macOS 会自动管理。
3、helpMenu:帮助菜单。
NSApp.helpMenu
访问并自定义菜单栏中最右侧的 “帮助”菜单。
五、Dock 图标控制
1、dockTile:控制 Dock 上的图标及 badge 等。
let dockTile = NSApp.dockTile
设置图标上的红点数字(badge):
dockTile.badgeLabel = "3"
移除Badge:
dockTile.badgeLabel = nil
设置 Dock 图标的自定义内容视图:
let label = NSTextField(labelWithString: "🐷")
label.alignment = .center
label.font = NSFont.systemFont(ofSize: 32)
NSApp.dockTile.contentView = label
NSApp.dockTile.display() // 一定要手动刷新
强制刷新 Dock 图标内容。
2、applicationIconImage:设置 Dock 图标。
NSApp.applicationIconImage = NSImage(named: "MyAppIcon")
更换 Dock 图标(例如运行期间换图标)。
注意:更换的是应用运行期间的 Dock 图标,而不是应用图标。
比 setApplicationIconImage(_:) 更推荐使用。
3、setApplicationIconImage(_:):更新图标(已弃用,改用上面属性)。
NSApp.setApplicationIconImage(myImage) // ⚠️ Deprecated
已被 applicationIconImage 属性替代。
在新项目中不建议使用。
六、代理与通知
1、NSApplicationDelegate:处理生命周期事件,如启动、终止、打开文件等。
常见方法有:
func applicationDidFinishLaunching(_ notification: Notification)
func applicationWillTerminate(_ notification: Notification)
func applicationDidBecomeActive(_ notification: Notification)
func applicationDidResignActive(_ notification: Notification)
func application(_ sender: NSApplication, openFile filename: String) -> Bool
使用方式:
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
print("App 启动完成")
}
func applicationWillTerminate(_ notification: Notification) {
print("App 即将退出")
}
}
2、.didFinishLaunchingNotification:启动完成通知。
NotificationCenter.default.addObserver(
forName: NSApplication.didFinishLaunchingNotification,
object: nil,
queue: .main
) { _ in
print("启动完成(通知方式)")
}
等价于 applicationDidFinishLaunching(_:) 的通知形式。
如果不能接入 delegate,也可以监听这个通知。
3、.willTerminateNotification:即将退出通知。
NotificationCenter.default.addObserver(
forName: NSApplication.willTerminateNotification,
object: nil,
queue: .main
) { _ in
print("App 即将退出,保存数据")
}
保存数据、释放资源的好时机。
系统关机、用户手动退出、Cmd+Q 都会触发。
4、.didBecomeActiveNotification:激活通知。
NotificationCenter.default.addObserver(
forName: NSApplication.didBecomeActiveNotification,
object: nil,
queue: .main
) { _ in
print("App 被激活(前台)")
}
App 从后台切换到前台。
或首次启动时。
可用于刷新 UI、恢复动画等。
5、.didResignActiveNotification:失去焦点通知。
NotificationCenter.default.addObserver(
forName: NSApplication.didResignActiveNotification,
object: nil,
queue: .main
) { _ in
print("App 进入后台(失去活跃)")
}
用户切换到其他 App。
或打开系统对话框、弹窗等。
七、其他有用功能
1、打开文件:openFile(_:) / openFiles(_:)(通常由 delegate 实现)。
需要配置Info.plist以及delegate,双击支持的文件时,macOS唤起App,并调用 openFiles()。
2、打开 URL:openURLs(_:)(10.15+)。
需要配置Info.plist以及delegate,用户在浏览器打开 myapp://something 时,macOS 会调用 openURLs(_:),类似深层链接。
这两个方法需要通过 delegate 实现,复杂一些,这里不做多解释。
NSApp创建过程
在 SwiftUI 中,NSApplicationMain() 是由 Swift 编译器自动调用的:
@main
struct MyApp: App { ... }
Swift 会调用 _startApp()(内部封装了 NSApplicationMain 的逻辑),并:
1、创建 NSApplication.shared。
2、设置 NSApp。
3、调用 SwiftUI 生命周期逻辑。
4、自动注册 @NSApplicationDelegateAdaptor 的 delegate。

注意:NSApp是单例,所以不应该手动创建多个NSApplication实例。
此外,还可以自定义NSApplication类:
@objc(MyApplication)
class MyApplication: NSApplication {
override func sendEvent(_ event: NSEvent) {
print("Intercepted:", event)
super.sendEvent(event)
}
}
在 Info.plist 中修改:
<key>NSPrincipalClass</key>
<string>MyApplication</string>
但是,在SwiftUI中并不会显式调用NSApplication.run(),它内部使用了更高层的抽象(调用了 _startApp() 等内部逻辑),某些事件不会通过重写的 sendEvent(_:) 方法分发。
因此需要手动调用run()以触发sendEvent(_:)。这部分比较复杂,不在这里赘述。
和 @NSApplicationDelegateAdaptor 关系
当创建Appdelegate后,在入口文件声明 @NSApplicationDelegateAdaptor:
@main
struct ImageSlimApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
...
}
SwiftUI在App初始化前,会创建自己指定的AppDelegate实例。
调用:
NSApp.delegate = appDelegate
在NSApp.run()执行前,触发:
appDelegate.applicationDidFinishLaunching(_:)
在退出前也会触发 applicationWillTerminate。
所以,@NSApplicationDelegateAdaptor的作用就是注册并持有一个生命周期代理(AppDelegate),同时自动接管 NSApp.delegate。
相关文章
SwiftUI macOS的commands菜单栏修饰符:https://fangjunyu.com/2025/06/19/swiftui-macos%e7%9a%84commands%e8%8f%9c%e5%8d%95%e6%a0%8f%e4%bf%ae%e9%a5%b0%e7%ac%a6/