如何重写windowDidLoad监听NSWindow加载?解决类型转换报错
问题解决与窗口加载监听方法
1. 修复类型转换错误
你遇到的Cannot convert value of type 'NSWindowController' to specified type 'MyNSWindowController'错误,是因为试图将父类NSWindowController的实例赋值给子类MyNSWindowController类型的变量,二者类型不兼容。
修正代码
将openInWindow方法中的错误行:
let myNSWindowController: MyNSWindowController = NSWindowController(window: window)
替换为直接初始化子类实例:
let myNSWindowController = MyNSWindowController(window: window)
关键补充
需要保留MyNSWindowController的引用,避免局部变量被立即释放导致windowDidLoad方法不执行。可以通过关联对象将控制器绑定到窗口上,修改后的完整openInWindow方法如下:
extension View { private static let windowControllerAssociatedKey = UnsafeRawPointer(bitPattern: "WindowControllerAssociatedKey".hashValue)! @discardableResult func openInWindow(title: String, sender: Any?) -> NSWindow { let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 500.0, height: 500.0), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) // 初始化自定义窗口控制器 let windowController = MyNSWindowController(window: window) // 将控制器绑定到窗口,避免被释放 objc_setAssociatedObject(window, Self.windowControllerAssociatedKey, windowController, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) window.title = title window.setFrameAutosaveName(title) window.isReleasedWhenClosed = false window.contentView = NSHostingView(rootView: self) window.center() window.makeKeyAndOrderFront(sender) return window } }
2. Cocoa中监听窗口加载的原生方法
方法一:NSWindowController的windowDidLoad()(推荐)
你重写的windowDidLoad()是Cocoa中专门监听窗口加载完成的方法,当窗口控制器关联的窗口完成初始化加载后会自动调用,这和SwiftUI的onAppear逻辑最匹配,是监听窗口自身加载完成的最优选择。
方法二:NSWindowDelegate的生命周期方法
如果不使用窗口控制器,可以通过设置NSWindow的delegate,实现以下方法:
windowDidBecomeMain(_ notification: Notification):窗口成为主窗口时触发(适合需要在窗口激活时执行的逻辑)windowWillLoad(_ notification: Notification):窗口即将开始加载时触发(较少使用,因为窗口初始化后通常会立即加载)
示例代码:
class MyWindowDelegate: NSObject, NSWindowDelegate { func windowDidBecomeMain(_ notification: Notification) { print("窗口已激活,可视为加载完成后进入可用状态") } } // 在创建窗口时设置代理 let delegate = MyWindowDelegate() window.delegate = delegate
方法三:监听NSWindow的通知
可以通过通知中心监听窗口状态变化的通知,比如:
NotificationCenter.default.addObserver(forName: NSWindow.didBecomeKeyNotification, object: window, queue: .main) { _ in print("窗口已成为关键窗口") }
但这类通知是基于窗口状态变化触发,并非严格意义上的"加载完成",windowDidLoad()仍是最精准的方案。
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

