SwiftUI中NSWindow.willCloseNotification触发所有窗口问题及解决问询
SwiftUI多平台应用监听特定窗口关闭通知的问题与解决方法
问题原因
你使用的NotificationCenter.default.publisher(for: NSWindow.willCloseNotification)是全局订阅,它会监听系统中所有NSWindow发出的关闭通知。虽然AppKit文档提到通知会发送给特定窗口对象,但默认的订阅没有过滤通知的object字段(即通知对应的窗口实例),因此所有订阅了该通知的View都会收到任意窗口的关闭事件,导致每个窗口关闭时所有View的清理闭包都被触发。
解决方法
要实现仅监听当前View所在窗口的关闭事件,核心是获取当前View对应的NSWindow实例,然后针对性地订阅通知或设置代理:
方法一:订阅特定窗口的通知
通过自定义NSViewRepresentable捕获当前View所在的窗口,然后订阅该窗口的willCloseNotification:
// 用于捕获当前View所在窗口的辅助View struct WindowCaptureView: NSViewRepresentable { let onWindowFound: (NSWindow) -> Void func makeNSView(context: Context) -> NSView { let view = NSView() // 延迟执行确保view已加入窗口层级 DispatchQueue.main.async { if let window = view.window { onWindowFound(window) } } return view } func updateNSView(_ nsView: NSView, context: Context) {} } // 在顶层View中使用 NavigationStack { // 你的视图内容 } .background(WindowCaptureView { window in // 仅订阅当前窗口的关闭通知 let closePublisher = NotificationCenter.default.publisher( for: NSWindow.willCloseNotification, object: window ) _ = closePublisher.sink { _ in // 执行当前窗口的清理操作 print("当前窗口关闭,执行清理") } })
通过指定object: window,发布者只会转发该窗口发出的关闭通知,实现精准监听。
方法二:设置NSWindowDelegate
通过窗口代理的windowWillClose方法处理清理逻辑,同样需要先捕获当前窗口:
// 自定义窗口代理类 class WindowCleanupDelegate: NSObject, NSWindowDelegate { private let cleanupAction: () -> Void init(cleanupAction: @escaping () -> Void) { self.cleanupAction = cleanupAction super.init() } func windowWillClose(_ notification: Notification) { cleanupAction() } } // 捕获窗口并设置代理的辅助View struct WindowDelegateView: NSViewRepresentable { let cleanupAction: () -> Void @State private var delegate: WindowCleanupDelegate? func makeNSView(context: Context) -> NSView { let view = NSView() DispatchQueue.main.async { if let window = view.window { delegate = WindowCleanupDelegate(cleanupAction: cleanupAction) window.delegate = delegate } } return view } func updateNSView(_ nsView: NSView, context: Context) {} } // 在顶层View中使用 NavigationStack { // 你的视图内容 } .background(WindowDelegateView { // 执行清理操作 })
这种方法更贴合AppKit的原生窗口生命周期处理逻辑,适合需要更复杂窗口管理的场景。
内容的提问来源于stack exchange,提问作者Duncan C
相关产品推荐
相关产品推荐

