Cocoa应用单窗口实例与关闭按钮处理崩溃问题求助
Cocoa状态栏应用窗口单实例与关闭后崩溃问题修复
问题描述
通过代码创建的Cocoa状态栏应用,点击第一个菜单项需打开单实例窗口(重复点击激活当前窗口),但关闭窗口后再次点击该菜单项会导致应用崩溃。
崩溃原因
默认情况下,NSWindow的isReleasedWhenClosed属性为true,关闭窗口时窗口实例会被释放。而代码中window是lazy属性,再次点击菜单项时会重新创建窗口,同时重复设置contentViewController等操作会引发异常。
修复步骤
- 禁止窗口关闭时释放实例:初始化窗口时设置
isReleasedWhenClosed = false,让关闭窗口仅隐藏而非销毁实例。 - 判断窗口状态,避免重复配置:点击菜单项时先检查窗口是否可见,若已显示则直接激活,无需重复执行初始化逻辑。
- 提前配置窗口内容:在窗口初始化阶段就设置好
contentViewController和标题,避免每次点击都重复赋值。
修改后的完整代码
import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { var statusItem: NSStatusItem! lazy var window: NSWindow = { let win = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 550, height: 300), styleMask: [.miniaturizable, .closable, .titled], backing: .buffered, defer: false) win.isReleasedWhenClosed = false // 关键:关闭窗口不释放实例 win.contentViewController = myViewController // 提前绑定控制器 win.title = "Open Network Share Url's" return win }() let myViewController = ViewController() func applicationDidFinishLaunching(_ aNotification: Notification) { statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let button = statusItem.button { button.image = NSImage(systemSymbolName: "1.circle", accessibilityDescription: "1") } setupMenus() } func setupMenus() { let menu = NSMenu() let one = NSMenuItem(title: "Open Network Share Url's", action: #selector(didTapOne), keyEquivalent: "1") menu.addItem(one) let two = NSMenuItem(title: "Reconnect", action: #selector(didTapTwo), keyEquivalent: "2") menu.addItem(two) menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu } private func changeStatusBarButton(number: Int) { if let button = statusItem.button { button.image = NSImage(systemSymbolName: "\(number).circle", accessibilityDescription: number.description) } } @objc func didTapOne() { changeStatusBarButton(number: 1) if window.isVisible { // 窗口已显示,直接激活前置 window.makeKeyAndOrderFront(nil) } else { // 窗口未显示,居中后显示 window.center() window.makeKeyAndOrderFront(nil) } NSApp.activate(ignoringOtherApps: true) } @objc func didTapTwo() { changeStatusBarButton(number: 2) } }
额外说明
- 设置
isReleasedWhenClosed = false后,窗口实例会保留至应用退出,完美实现单实例需求。 - 通过判断窗口可见性,避免了重复初始化带来的性能损耗和异常风险。
内容的提问来源于stack exchange,提问作者AppleDeveloper
相关产品推荐
相关产品推荐

