
NSWindowController
-
NSWindowController是用來管理window的控制器,能夠管理xib或storyboard文件中加載的窗口視圖。在Document-Based應(yīng)用中,NSWindowController也負(fù)責(zé)創(chuàng)建和管理document的window。 - NSWindowController在基于UI界面的應(yīng)用中,管理不同場景多個(gè)界面窗口的切換,可以說起了非常重要的作用。
- 創(chuàng)建基于xib的一個(gè)NSWindowController類后就自動(dòng)完成了NSWindow的創(chuàng)建,因此一般情況下很少單獨(dú)去創(chuàng)建一個(gè)獨(dú)立的NSWindow,只需要調(diào)用NSWindowController的
showWindow方法顯示window就可以了。
加載過程
1. 使用Xib
- 1).
LoadNib: NSApplication運(yùn)行后加載xib文件 - 2).
orderFront:創(chuàng)建window對(duì)象顯示window - 3).
makeKey:app啟動(dòng)完成后,使當(dāng)前window成為keyWindow
2. 使用Storyboard
- 1).
LoadNib: NSApplication運(yùn)行后加載Storyboard文件 - 2).
makeKeyAndOrderFront:等價(jià)執(zhí)行了orderFront和makeKey
關(guān)閉過程
- 1). 執(zhí)行NSWindow的
close方法 - 2). 執(zhí)行
orderOut方法
NSWindowDelegate
常用代理
- 調(diào)整Windows大小
// 窗口大小將要變更
func windowWillResize(NSWindow, to: NSSize) -> NSSize
// 窗口大小已經(jīng)變更
func windowDidResize(Notification)
- 最小化Windows
// 窗口將要最小化
func windowWillMiniaturize(Notification)
// 窗口已經(jīng)最小化
func windowDidMiniaturize(Notification)
- 全屏Windows
// 窗口即將進(jìn)入全屏模式
func windowWillEnterFullScreen(Notification)
// 窗口已進(jìn)入全屏模式
func windowDidEnterFullScreen(Notification)
// 窗口即將退出全屏模式
func windowWillExitFullScreen(Notification)
// 窗口已退出全屏模式
func windowDidExitFullScreen(Notification)
- 窗口移動(dòng)
// 窗口將要移動(dòng)
func windowWillMove(Notification)
// 窗口已移動(dòng)
func windowDidMove(Notification)
- 關(guān)閉窗口
// 用戶試圖關(guān)閉窗口,return 是否允許關(guān)閉
func windowShouldClose(NSWindow) -> Bool
// 窗口即將關(guān)閉
func windowWillClose(Notification)
- KeyWindow (接收鍵盤鼠標(biāo)事件的窗口)
// 窗口已成為KeyWindow
func windowDidBecomeKey(Notification)
// 窗口已退出KeyWindow狀態(tài)
func windowDidResignKey(Notification)
常見問題
1.實(shí)現(xiàn)懶加載的屬性方法
lazy var myWindow = { () -> NSWindow in
let frame = CGRect(x: 0, y: 0, width: 400, height: 280)
let style : NSWindow.StyleMask = [NSWindow.StyleMask.titled,NSWindow.StyleMask.closable,NSWindow.StyleMask.resizable]
//創(chuàng)建window
let myWindow = NSWindow(contentRect:frame, styleMask:style, backing:.buffered, defer:false)
myWindow.title = "New Create Window"
return NSWindow.init()
}()
2.定義按鈕的點(diǎn)擊事件,顯示myWindow
func showWindowAction(_ sender: NSButton) {
self.myWindow.makeKeyAndOrderFront(self)
}
你會(huì)發(fā)現(xiàn)只有第一次你可以正常的呼出myWindow顯示到屏幕上,當(dāng)你關(guān)閉這個(gè)window。再次點(diǎn)擊button時(shí)程序crash了!
這是因?yàn)槲覀冸m然強(qiáng)引用了myWindow,但是對(duì)于window的釋放,系統(tǒng)是特殊處理,只要關(guān)閉就釋放了.
- 使用NSWindowController管理Window
lazy var myWindowController = { () -> NSWindowController in
let myWindowController = NSWindowController.init()
self.myWindow.windowController = myWindowController
myWindowController.window = self.myWindow
return myWindowController
}()
這樣重新運(yùn)行App,反復(fù)關(guān)閉window在點(diǎn)擊button打開,沒有crash,一切很正常。
這樣我們可以得出一個(gè)結(jié)論:手工創(chuàng)建的NSWindow,關(guān)閉后系統(tǒng)會(huì)檢查這個(gè)window有沒有
controller引用它,有的話就不會(huì)釋放這個(gè)window對(duì)象。xib中創(chuàng)建的window則沒有這個(gè)問題。
AppDelegate中Window管理分離
新建一個(gè)NSWindowArchitecture項(xiàng)目工程
MainMenu.xib中默認(rèn)生成一個(gè)Window,這個(gè)Window是由AppDelegate負(fù)責(zé)管理的,從應(yīng)用的單一職責(zé)劃分的原則考慮,Window適合由獨(dú)立的NSWindowController去管理。
刪除點(diǎn)擊Window對(duì)象

新建一個(gè)文件AppMainWindowController,繼承NSWindowController,勾選使用xib修改AppMainWindowController中默認(rèn)的代碼,增加窗口居中顯示,返回window的xib文件名。
class AppMainWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
window?.center()
}
override var windowNibName: NSNib.Name? {
get{
return NSNib.Name(rawValue: "AppMainWindowController")
}
}
}
AppDelegate中增加AppMainWindowController的相關(guān)代碼
class AppDelegate: NSObject, NSApplicationDelegate {
lazy var windowController: AppMainWindowController = {
let wondowVC = AppMainWindowController()
return wondowVC
}()
func applicationDidFinishLaunching(_ aNotification: Notification) {
self.windowController.showWindow(self)
}
}
直接使用xib創(chuàng)建的工程和分離window調(diào)整后的架構(gòu)對(duì)比,可以看出架構(gòu)2在擴(kuò)展和維護(hù)性方面都代于架構(gòu)1

如果我們創(chuàng)建工程的時(shí)候勾選是使用Storyboard選項(xiàng),系統(tǒng)會(huì)創(chuàng)建Window Controller和View Controller Scene不同的分層的場景,這種架構(gòu)劃分是非常合理的。所以推薦使用Storyboard來完成工程創(chuàng)建.