NSWindowController (窗口控制器)

NSWindowController

  • NSWindowController是用來管理window的控制器,能夠管理xibstoryboard文件中加載的窗口視圖。在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í)行了orderFrontmakeKey

關(guān)閉過程

  • 1). 執(zhí)行NSWindow的close方法
  • 2). 執(zhí)行orderOut方法

NSWindowDelegate

常用代理

    1. 調(diào)整Windows大小
// 窗口大小將要變更
func windowWillResize(NSWindow, to: NSSize) -> NSSize
// 窗口大小已經(jīng)變更
func windowDidResize(Notification)
    1. 最小化Windows
// 窗口將要最小化
func windowWillMiniaturize(Notification)
// 窗口已經(jīng)最小化
func windowDidMiniaturize(Notification)
    1. 全屏Windows
// 窗口即將進(jìn)入全屏模式
func windowWillEnterFullScreen(Notification)
// 窗口已進(jìn)入全屏模式
func windowDidEnterFullScreen(Notification)
// 窗口即將退出全屏模式
func windowWillExitFullScreen(Notification)
// 窗口已退出全屏模式
func windowDidExitFullScreen(Notification)
    1. 窗口移動(dòng)
// 窗口將要移動(dòng)
func windowWillMove(Notification)
// 窗口已移動(dòng)
func windowDidMove(Notification)
    1. 關(guān)閉窗口
// 用戶試圖關(guān)閉窗口,return 是否允許關(guān)閉
func windowShouldClose(NSWindow) -> Bool
// 窗口即將關(guān)閉
func windowWillClose(Notification)
    1. 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)閉就釋放了.

  1. 使用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 ControllerView Controller Scene不同的分層的場景,這種架構(gòu)劃分是非常合理的。所以推薦使用Storyboard來完成工程創(chuàng)建.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容