从Dock退出时应用崩溃报Thread 1: signal SIGTERM错误
问题描述
使用主文件+AppDelegate编写的macOS应用,从Dock右键选择“Quit”退出时,频繁在nsApplication.run()行崩溃,报错“Thread 1: signal SIGTERM”。已实现deinit、applicationShouldTerminate和applicationWillTerminate方法,但崩溃时控制台无日志输出;偶尔能正常退出并看到预期打印,ContentView为简单的“Hello, World!”视图。
代码片段
主文件
import Cocoa let nsApplication: NSApplication = NSApplication.shared let appDelegate: AppDelegate = AppDelegate() nsApplication.delegate = appDelegate nsApplication.run()
AppDelegate
import Cocoa import SwiftUI class AppDelegate: NSObject, NSApplicationDelegate { private lazy var window: NSWindow = NSWindow() deinit { print("AppDelegate is being deallocated") } func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { print("terminateNow") return .terminateNow } func applicationWillTerminate(_ notification: Notification) { print("Application will terminate") } func applicationDidFinishLaunching(_ aNotification: Notification) { window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView] window.backingType = .buffered window.isReleasedWhenClosed = false window.center() window.setFrameAutosaveName("Main Window") window.title = "Window" window.isMovableByWindowBackground = true window.contentView = NSHostingView(rootView: ContentView()) window.makeKeyAndOrderFront(nil) } }
ContentView
import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundColor(.accentColor) Text("Hello, world!") } .frame(width: 400.0, height: 200.0) } }
解决方案
1. 完善应用初始化流程
手动启动NSApplication时,需明确设置应用激活策略,确保系统能正确识别应用状态,避免终止时的异常:
修改主文件代码:
import Cocoa let nsApplication = NSApplication.shared let appDelegate = AppDelegate() nsApplication.delegate = appDelegate nsApplication.setActivationPolicy(.regular) // 新增:设置应用为前台激活状态 nsApplication.run()
2. 主动清理终止时的资源
在applicationWillTerminate中手动关闭窗口,确保SwiftUI宿主视图及相关资源提前完成清理:
func applicationWillTerminate(_ notification: Notification) { print("Application will terminate") window.close() // 手动触发窗口资源释放 }
3. 调整窗口生命周期管理
将窗口的isReleasedWhenClosed改为true,让系统自动管理窗口的释放流程,减少手动控制的风险:
func applicationDidFinishLaunching(_ aNotification: Notification) { window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView] window.backingType = .buffered window.isReleasedWhenClosed = true // 修改为自动释放窗口 window.center() window.setFrameAutosaveName("Main Window") window.title = "Window" window.isMovableByWindowBackground = true window.contentView = NSHostingView(rootView: ContentView()) window.makeKeyAndOrderFront(nil) }
4. 改用标准启动方式(推荐)
如果无需手动控制NSApplication启动流程,使用系统标准的NSApplicationMain启动方式,由系统托管应用生命周期,避免手动初始化的边缘问题:
替换主文件代码:
import Cocoa NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
并在Info.plist中添加配置:
- 设置
NSPrincipalClass为NSApplication - 设置
NSMainNibFile为空字符串 - 添加
NSApplicationDelegateClass,值为你的AppDelegate类的完整类名(例如$(PRODUCT_MODULE_NAME).AppDelegate)
或直接在AppDelegate类上添加@NSApplicationMain注解,自动完成上述配置:
@NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { // ... 原有代码 ... }
原因说明
崩溃的核心是手动初始化NSApplication时,应用状态未正确设置,或终止流程中资源清理不及时,导致系统发送SIGTERM信号时出现内存访问异常。上述方案通过规范应用状态、主动清理资源或交由系统托管生命周期,解决了竞态条件和资源残留问题。
内容的提问来源于stack exchange,提问作者Mango

