🐰

NSWindowControllerでNSWindowDelegateを捕まえるにはコツがいる

2024/02/27に公開

NSWindowControllerをNSWindowDelegateにしてもメッセージが飛んでこない場合がある

AppKitNSWindowに関するさまざまな通知はNSWindowDelegateで検知できる仕組みです。しかし、NSWindowControllerに管理されているウインドウオブジェクトの場合、NSWindowControllerオブジェクトをデリゲートを指定しても、各デリゲートメソッドにメッセージが一切飛んでこないといった不可解な現象が生じるようです。

Interface Builderでdelegateを指定したり、どこかのイニシャライザでそれを行なっていても、これはうまくいかないようです。

showWindow(_:)でデリゲートを再設定するとうまくいく

NSWindowController.showWindow(_:)をオーバーライドし、superのコール前にウインドウオブジェクトのデリゲートを再設定してあげることでこの不可解な現象を解消できました。

// MyWindowController.swift

override func showWindow(_ sender: Any?) {
	window?.delegate = self // ここで delegate を再設定しないとダメ
	super.showWindow(sender)
}


// MARK: - NSWindowDelegate

func windowDidBecomeKey(_ notification: Notification) {
	// showWindow(_:) tweak によって正しくコールされるようになる
}
	
func windowDidResignKey(_ notification: Notification) {
	// showWindow(_:) tweak によって正しくコールされるようになる
}

ちなみに新しく作ったNSWindowControllerのインスタンスオブジェクトはきちんと誰かが保持しておかないと自動解放されてしまうので、Document-basedではない独自の仕組みであるならこの処理もデベロッパー自身が行う必要があります。

(NSViewController, UIViewControllerのノリで扱うとこの保持し忘れが起きがちです。)

Discussion