You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)")
                }
        }
    }
}

关键要点说明

  1. 获取触发通知的窗口:每个窗口通知的object属性就是对应的NSWindow实例,这是区分窗口的核心依据。
  2. 避免全局共享标识:App结构体是单例,里面的属性会被所有窗口共享,所以不能在这里定义窗口级别的唯一标识。
  3. 窗口唯一属性选择:windowNumber是系统保证唯一的,适合快速实现;自定义UUID则更灵活,适合需要持久化或自定义逻辑的场景。

内容的提问来源于stack exchange,提问作者swiftPunk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:31:12