SwiftUI macOS中如何让窗口可识别?多窗口焦点追踪问题
解决SwiftUI多窗口聚焦追踪的区分问题
你的问题核心在于:App结构体里定义的uuid是全局单例属性,整个App运行期间只会生成一次,所以所有新建窗口的ContentView都会共享这个UUID,自然无法区分不同窗口。另外,通知的hashValue是通知对象自身的哈希值,不是对应窗口的唯一标识,所以也不能用来区分窗口。
正确的解决思路
要区分不同窗口,关键是从通知中获取触发通知的NSWindow实例,然后用窗口自身的唯一属性(比如系统分配的windowNumber)或者给每个窗口绑定自定义唯一标识来区分。
修改后的代码示例
方案1:直接使用系统分配的窗口编号(最简单)
窗口的windowNumber是系统自动分配的唯一整数,不需要额外设置:
@main struct oioApp: App { var body: some Scene { WindowGroup { ContentView() .onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeMainNotification)) { notification in guard let window = notification.object as? NSWindow else { return } print("Focused = true", "窗口编号: \(window.windowNumber)") } .onReceive(NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)) { notification in guard let window = notification.object as? NSWindow else { return } print("Focused = false", "窗口编号: \(window.windowNumber)") } } } }
方案2:给每个窗口绑定自定义UUID
如果需要自己管理唯一标识,可以把UUID绑定到窗口的representedObject属性:
@main struct oioApp: App { var body: some Scene { WindowGroup { ContentView() .onAppear { // 窗口出现时,给当前窗口绑定唯一UUID if let currentWindow = NSApplication.shared.keyWindow { currentWindow.representedObject = UUID() } } .onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeMainNotification)) { notification in guard let window = notification.object as? NSWindow, let windowUUID = window.representedObject as? UUID else { return } print("Focused = true", "窗口UUID: \(windowUUID)") } .onReceive(NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification)) { notification in guard let window = notification.object as? NSWindow, let windowUUID = window.representedObject as? UUID else { return } print("Focused = false", "窗口UUID: \(windowUUID)") } } } }
关键要点说明
- 获取触发通知的窗口:每个窗口通知的
object属性就是对应的NSWindow实例,这是区分窗口的核心依据。 - 避免全局共享标识:App结构体是单例,里面的属性会被所有窗口共享,所以不能在这里定义窗口级别的唯一标识。
- 窗口唯一属性选择:
windowNumber是系统保证唯一的,适合快速实现;自定义UUID则更灵活,适合需要持久化或自定义逻辑的场景。
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

