如何實(shí)現(xiàn)單窗口多標(biāo)簽文檔Mac應(yīng)用

創(chuàng)建Document應(yīng)用絮记,默認(rèn)情況下,啟動(dòng)應(yīng)用就會(huì)彈出一個(gè)窗口省核,此時(shí)一個(gè)NSDocument對(duì)應(yīng)一個(gè)NSWindowController掂僵。如果要new一個(gè)新的文檔航厚,這個(gè)時(shí)候就會(huì)彈出一個(gè)新的窗口。如果我們想要?jiǎng)?chuàng)建一個(gè)應(yīng)用锰蓬,每次new/open一個(gè)文檔的時(shí)候幔睬,該文檔都在一個(gè)窗口上創(chuàng)建或打開(kāi),就是用單窗口容納多個(gè)文檔(譬如瀏覽器用單窗口容納多個(gè)標(biāo)簽頁(yè)面芹扭,word文檔用單窗口容納多個(gè)文檔)麻顶,我們?cè)撛趺磳?shí)現(xiàn)呢。

首先我們先搞清楚NSDocumentController舱卡、NSDocument辅肾、NSWindowController、NSWindow四者的關(guān)系轮锥,通常情況下矫钓,文檔應(yīng)用只有一個(gè)NSDocumentController對(duì)象。新建一個(gè)文檔過(guò)程:首先創(chuàng)建一個(gè)NSDocument對(duì)象,這個(gè)對(duì)象會(huì)被NSDocumentController對(duì)象調(diào)用addDocument方法來(lái)加到自己的documents容器去新娜,然后系統(tǒng)會(huì)調(diào)用文檔的makeWindowControllers方法來(lái)創(chuàng)建自己的NSWindowController對(duì)象赵辕,將NSDocument與NSWindowController一一匹配。makeWindowControllers默認(rèn)實(shí)現(xiàn)就是加載指定的nib文件來(lái)創(chuàng)建自己的windowcontroller概龄。為了實(shí)現(xiàn)單窗口多文檔还惠,這個(gè)時(shí)候我們就需要一個(gè)NSWindowController對(duì)應(yīng)N個(gè)NSDocument,我們需要重載NSWindowController來(lái)實(shí)現(xiàn)我們自己的windowController私杜,且該windowController支持單例模式蚕键,就是只有唯一的一個(gè)NSWindowController對(duì)象,這樣就只有唯一的一個(gè)文檔窗口(NSWindowController對(duì)應(yīng)一個(gè)NSWindow衰粹,也對(duì)應(yīng)一個(gè)包含window的nib/xib文件)锣光。

makeWindowControllers實(shí)現(xiàn)代碼:

- (void)makeWindowControllers{

? ? [self addWindowController:[MyMainWindowController shareMainWindowController]];

}

雖然說(shuō)這樣實(shí)現(xiàn)可以保證我們新建或打開(kāi)文檔都只有唯一個(gè)窗口,但是如何將多文檔在一個(gè)窗口顯示呢寄猩?首先我想到的實(shí)現(xiàn)方式是用兩個(gè)NSCollectionView來(lái)實(shí)現(xiàn)嫉晶,一個(gè)用來(lái)裝標(biāo)簽,另一個(gè)用來(lái)裝文檔田篇,當(dāng)我們新建一個(gè)文檔的時(shí)候,我們就讓兩個(gè)collectionView同時(shí)reloadData來(lái)刷新界面箍铭,有多少個(gè)文檔泊柬,就有多少個(gè)標(biāo)簽,一個(gè)文檔與一個(gè)標(biāo)簽一一對(duì)應(yīng)诈火。實(shí)現(xiàn)邏輯是想到了兽赁,但是問(wèn)題是在哪里調(diào)用reloadData來(lái)刷新界面是關(guān)鍵。

這個(gè)時(shí)候我們就要來(lái)理清楚新建文檔冷守、打開(kāi)文檔刀崖、打開(kāi)最近、本地目錄雙擊文件打開(kāi)拍摇、應(yīng)用異常后下次自動(dòng)打開(kāi)都會(huì)涉及到那些內(nèi)部函數(shù)了亮钦。通過(guò)跟蹤這些步驟發(fā)現(xiàn),只需要重載三個(gè)函數(shù):

1,新建文件

- (__kindof NSDocument *)openUntitledDocumentAndDisplay:(BOOL)displayDocument error:(NSError *__autoreleasing? _Nullable *)outError;

2充活,打開(kāi)文件蜂莉,打開(kāi)最近菜單文件,雙擊文件打開(kāi)應(yīng)用會(huì)調(diào)用這個(gè)函數(shù)

- (void)openDocumentWithContentsOfURL:(NSURL *)url display:(BOOL)displayDocument completionHandler:(void (^)(NSDocument * _Nullable, BOOL, NSError * _Nullable))completionHandler;

3混卵,保存過(guò)的文件再編輯異常后映穗,或者新建文件編輯后沒(méi)保存過(guò)異常會(huì)調(diào)用這個(gè)函數(shù)來(lái)打開(kāi)

- (void)reopenDocumentForURL:(NSURL *)urlOrNil withContentsOfURL:(NSURL *)contentsURL display:(BOOL)displayDocument completionHandler:(void (^)(NSDocument * _Nullable, BOOL, NSError * _Nullable))completionHandler;

我們只需要重載這三個(gè)函數(shù),添加我們的刷新兩個(gè)NSCollectionView的代碼幕随,就能實(shí)現(xiàn)單窗口多標(biāo)簽文檔蚁滋。

到這里似乎好像就已經(jīng)完成了單窗口多標(biāo)簽文檔了,但其實(shí)還沒(méi)有完的。我們知道系統(tǒng)默認(rèn)是一個(gè)NSDocument對(duì)應(yīng)一個(gè)NSWindowController的辕录,此時(shí)我們窗口上有多個(gè)文檔澄阳,而只有一個(gè)NSWindowController,而NSWindowController它有一個(gè)成員document踏拜,就是記錄NSWindowController對(duì)應(yīng)的文檔∷橛現(xiàn)在乍看完了,怎么辦速梗,好像需要一一對(duì)應(yīng)肮塞,感覺(jué)做不到單窗口對(duì)應(yīng)多文檔了。

首先我想到的是姻锁,我們能不能在點(diǎn)擊標(biāo)簽的時(shí)候相應(yīng)的修改document變量到正確的文檔去枕赵,就是相應(yīng)的切換NSDocumentController的currentDocument對(duì)象,通過(guò)修改document變量好像還真的相應(yīng)的改變了currentDocument位隶,但是還是發(fā)現(xiàn)問(wèn)題了拷窜,當(dāng)我編輯了一個(gè)文檔后,切換到另一個(gè)文檔后再切換回來(lái)涧黄,我的編輯狀態(tài)丟失了(就是標(biāo)題欄中-Edited標(biāo)志不見(jiàn)了篮昧,該文檔相當(dāng)于沒(méi)編輯過(guò)了,如果關(guān)閉窗口或關(guān)閉應(yīng)用笋妥,不會(huì)詢問(wèn)是否要保存文檔而只會(huì)默認(rèn)關(guān)閉導(dǎo)致數(shù)據(jù)丟失了)懊昨。換句話說(shuō),簡(jiǎn)單的賦值document來(lái)改變currentDocument是有問(wèn)題的春宣,查看document屬性相關(guān)文檔酵颁,也建議不要修改該變量。這下徹底沒(méi)轍了月帝,還有辦法在點(diǎn)擊標(biāo)簽切換文檔時(shí)能改變NSWindowController中的document屬性和NSDocumentController中的currentDocument嗎躏惋?

答案是有的,我們只需要在點(diǎn)擊標(biāo)簽切換文檔的時(shí)候調(diào)用文檔的makeWindowControllers方法嚷辅,它會(huì)幫我們實(shí)現(xiàn)這一切簿姨,真的是謝天謝地啊。(關(guān)于點(diǎn)擊標(biāo)簽展示相應(yīng)的文檔只需要滾動(dòng)到相應(yīng)的文檔位置潦蝇,而鼠標(biāo)滑動(dòng)文檔切換也只需要變更標(biāo)簽的選中狀態(tài)來(lái)表示標(biāo)簽變化款熬,這些都很好實(shí)現(xiàn)就不一一討論)

到這里我們基本已經(jīng)實(shí)現(xiàn)了單窗口多標(biāo)簽文檔的編輯保存及在打開(kāi),但是還有最后一個(gè)問(wèn)題需要解決攘乒。雖然在退出應(yīng)用的時(shí)候系統(tǒng)會(huì)咨詢我們是否要處理多個(gè)編輯過(guò)的文檔贤牛,這個(gè)時(shí)候我們保存或者不處理都沒(méi)有問(wèn)題。但是则酝,如果編輯過(guò)多個(gè)文檔后點(diǎn)擊窗口的關(guān)閉按鈕就沒(méi)有那么順利了殉簸,因?yàn)榇丝痰膚indow只知道一個(gè)文檔闰集,就是NSWindowController的屬性document記錄的那個(gè)文檔,也是NSDocumentController中的currentDocument般卑。系統(tǒng)只會(huì)詢問(wèn)是否處理該文檔武鲁,而其它文檔會(huì)忽略掉。下次打開(kāi)應(yīng)用的時(shí)候蝠检,因?yàn)橹坝行┪臋n并沒(méi)有從NSDocumentController中移除沐鼠,系統(tǒng)會(huì)當(dāng)是異常了而重新打開(kāi)那些文檔。雖然似乎沒(méi)什么問(wèn)題叹谁,但顯然這不是我們要的結(jié)果饲梭。我們想當(dāng)然是希望我們點(diǎn)擊窗口關(guān)閉按鈕的時(shí)候跟退出應(yīng)用一樣,能詢問(wèn)我們時(shí)候處理所有編輯過(guò)的文檔焰檩,而不是只處理當(dāng)前文檔憔涉。

此時(shí),我們要做的事情就是重新實(shí)現(xiàn)窗口關(guān)閉的功能啦析苫。具體如下:

? ? NSButton* closeButton = [self.window standardWindowButton:NSWindowCloseButton];

? ? [closeButton setTarget:self];

? ? [closeButton setAction:@selector(closeWindow:)];

closeWindow的實(shí)現(xiàn)兜叨,一個(gè)簡(jiǎn)單的方式就是調(diào)用終止應(yīng)用的代碼,這個(gè)時(shí)候點(diǎn)擊窗口關(guān)閉和退出應(yīng)用的過(guò)程如出一轍衩侥,都會(huì)提示是否要處理編輯過(guò)的文檔国旷。但又有問(wèn)題,此時(shí)應(yīng)用會(huì)完全退出啦顿乒,如果我們只想做到關(guān)閉窗口而不退出應(yīng)用议街,我們可以遍歷documents對(duì)象,逐個(gè)檢查是否編輯過(guò)璧榄,編輯過(guò)的文檔調(diào)用- (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo來(lái)彈出窗口來(lái)處理。

到這里基本解決所有遇到的問(wèn)題了吧雹,通常我們可能還想把NSCollectionView中的滾動(dòng)條隱藏掉骨杂。看似隱藏滾動(dòng)條是非常簡(jiǎn)單的事雄卷,但如果大家在添加NSCollectionView的時(shí)候是直接在xib/nib可視文檔上添加的搓蚪,那就會(huì)遇到設(shè)置NSScrollView的NSScroller隱藏?zé)o效,怎么自定義都沒(méi)用丁鹉,關(guān)于如何隱藏滾動(dòng)條請(qǐng)參考我寫的另外一篇文章了妒潭。文章鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市揣钦,隨后出現(xiàn)的幾起案子雳灾,更是在濱河造成了極大的恐慌,老刑警劉巖冯凹,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谎亩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)匈庭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門夫凸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人阱持,你說(shuō)我怎么就攤上這事夭拌。” “怎么了衷咽?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鸽扁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我兵罢,道長(zhǎng)献烦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任卖词,我火速辦了婚禮巩那,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘此蜈。我一直安慰自己即横,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布裆赵。 她就那樣靜靜地躺著东囚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪战授。 梳的紋絲不亂的頭發(fā)上页藻,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音植兰,去河邊找鬼份帐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛楣导,可吹牛的內(nèi)容都是我干的废境。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼筒繁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼噩凹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起毡咏,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤驮宴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后血当,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體幻赚,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡禀忆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了落恼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箩退。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖佳谦,靈堂內(nèi)的尸體忽然破棺而出戴涝,到底是詐尸還是另有隱情,我是刑警寧澤钻蔑,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布啥刻,位于F島的核電站,受9級(jí)特大地震影響咪笑,放射性物質(zhì)發(fā)生泄漏可帽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一窗怒、第九天 我趴在偏房一處隱蔽的房頂上張望映跟。 院中可真熱鬧,春花似錦扬虚、人聲如沸努隙。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)荸镊。三九已至,卻和暖如春堪置,著一層夾襖步出監(jiān)牢的瞬間躬存,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工舀锨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留优构,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓雁竞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拧额。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碑诉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 相較于 iOS 上火熱的開(kāi)發(fā)勢(shì)頭,macOS 開(kāi)發(fā)簡(jiǎn)直就是一片藍(lán)海侥锦。讓人不禁有些好奇进栽,本是同根生的 macOS 開(kāi)...
    davidleee閱讀 6,235評(píng)論 6 9
  • 窗口是所有 OS X app 的 UI “容器”。它定義了 app 當(dāng)前負(fù)責(zé)的屏幕區(qū)域恭垦,并且允許用戶用通用的模式(...
    張嘉夫閱讀 8,943評(píng)論 4 51
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,100評(píng)論 1 32
  • 因?yàn)橐Y(jié)局swift3.0中引用snapKit的問(wèn)題,看到一篇介紹Xcode8,swift3變化的文章,覺(jué)得很詳細(xì)...
    uniapp閱讀 4,414評(píng)論 0 12
  • 前言 關(guān)于UIWebView的介紹快毛,相信看過(guò)上文的小伙伴們格嗅,已經(jīng)大概清楚了吧,如果有問(wèn)題唠帝,歡迎提問(wèn)屯掖。 本文是本系列...
    CoderLF閱讀 8,965評(píng)論 2 12