如何实现NSWindow程序化创建与销毁的正确生命周期?
程序化创建NSWindow的正确生命周期实现
问题根源分析
你的代码存在两个核心问题:
- 直接持有
NSWindow实例而非NSWindowController,违背了Apple设计的窗口生命周期管理逻辑——NSWindowController才是负责窗口创建、显示、销毁全生命周期的容器类。 - 局部创建的
NSWindowController会被ARC立即释放,导致窗口失去正确的管理容器;而直接移除windowController后,窗口被提前释放但系统仍有后续消息发送,引发野指针崩溃。
修正后的代码实现
class Wins: NSObject, NSWindowDelegate { // 改为持有NSWindowController,而非直接持有NSWindow private var windowControllers = Set<NSWindowController>() func createWindow() { let newWindow = NSWindow( contentRect: .init(origin: .zero, size: .init(width: 300, height: 300)), styleMask: [.titled, .closable, .miniaturizable, .resizable], // 用枚举替代rawValue,可读性更强 backing: .buffered, defer: false ) newWindow.title = "New Window" newWindow.isOpaque = false newWindow.isMovableByWindowBackground = true newWindow.backgroundColor = NSColor(calibratedHue: 0, saturation: 1.0, brightness: 0, alpha: 0.7) newWindow.delegate = self // 设置代理监听窗口关闭事件 let windowController = NSWindowController(window: newWindow) windowController.window?.makeKeyAndOrderFront(nil) windowControllers.insert(windowController) // 强引用控制器,维持其生命周期 } // 监听窗口即将关闭事件,自动清理控制器引用 func windowWillClose(_ notification: Notification) { guard let window = notification.object as? NSWindow, let controller = window.windowController else { return } windowControllers.remove(controller) } func closeAll() { // 遍历集合副本,避免遍历过程中修改原集合引发异常 for controller in windowControllers { controller.close() } } }
关键修正点说明
- 用NSWindowController管理窗口:
NSWindowController会自动处理窗口的内存管理逻辑,避免手动持有窗口导致的引用循环或释放不及时问题。当控制器被释放时,其持有的窗口也会被正确回收。 - 实现windowWillClose代理:窗口关闭时触发该方法,从集合中移除对应的控制器,解除强引用,让ARC可以正常回收控制器和窗口的内存。
- 避免直接遍历修改集合:关闭所有窗口时遍历集合的副本,防止遍历过程中集合元素被移除导致的遍历异常。
内容的提问来源于stack exchange,提问作者gcstr
相关产品推荐
相关产品推荐

