翻譯:iOS視圖控制器編程指南(七)——保存和恢復(fù)狀態(tài)(Preserving and Restoring State)

視圖控制器在保存和恢復(fù)過程中起著非常重要的作用。狀態(tài)保存記錄應(yīng)用中斷前的配置,在隨后應(yīng)用啟動恢復(fù)配置。將應(yīng)用恢復(fù)到先前的配置可以為用戶節(jié)省時(shí)間,并提供一個(gè)更好的用戶體驗(yàn)。

保存和恢復(fù)過程是自動的,但你需要告訴iOS,需要保留應(yīng)用的哪些部分。保存應(yīng)用視圖控制器的步驟如下:

· (必須)分配恢復(fù)標(biāo)示符到你想保存的視圖控制器上,參見標(biāo)記保存視圖控制器( Tagging View Controllers for Preservation

· (必須)告訴iOS如何在啟動時(shí)創(chuàng)建或查找新視圖控制器對象,參見啟動時(shí)恢復(fù)視圖控制器( Restoring View Controllers at Launch Time)。

· (可選)每個(gè)視圖控制器,存儲任何特定配置數(shù)據(jù)使視圖控制器返回到原來的配置,參見視圖控制器狀態(tài)的編碼和解碼(Encoding and Decoding Your View Controller’s State)。

保存和恢復(fù)的過程的概述,參見iOS應(yīng)用編程指南(App Programming Guide for iOS)。

標(biāo)記保存視圖控制器

UIKit只保存你告訴它要保存的視圖控制器。每個(gè)視圖控制器有一個(gè)restorationIdentifier屬性,這個(gè)屬性的默認(rèn)值為nil。設(shè)置這個(gè)屬性值為有效字符串,告訴UIKit視圖控制器和視圖應(yīng)該要保存。可以以編程的方式或者在storyboard文件中設(shè)置恢復(fù)標(biāo)示符。

當(dāng)分配恢復(fù)標(biāo)示符時(shí),在視圖層級結(jié)構(gòu)中的所有的父視圖控制器必須有恢復(fù)標(biāo)示符。在保存過程中,UIKit從窗口的根視圖控制器開始并遍歷視圖控制器層級結(jié)構(gòu)。如果該層級結(jié)構(gòu)中一個(gè)視圖控制器沒有恢復(fù)標(biāo)示符,該視圖控制器和其所有子視圖控制器和present的視圖控制器都會被忽略。

選擇有效的恢復(fù)標(biāo)示符

UIKit使用恢復(fù)標(biāo)示符字符串在之后重新創(chuàng)建視圖控制器,所以必須選擇代碼容易識別的字符串。如果UIKit不能自動創(chuàng)建一個(gè)視圖控制器,要求你創(chuàng)建,UIKit會提供視圖控制器和其所有父視圖控制器的恢復(fù)標(biāo)示符。這一串的標(biāo)示符代表視圖控制器的恢復(fù)路徑,及如何決定哪些視圖控制器被請求。恢復(fù)路徑從根視圖控制器開始,包括呈現(xiàn)的每個(gè)視圖控制器和被請求的視圖控制器。

恢復(fù)標(biāo)示圖通常以視圖控制器類名命名。如果你在很多地方使用相同的類,你可能希望分配更有意義的值。例如,你可以基于視圖控制器管理的數(shù)據(jù)來指定字符串。

每個(gè)視圖控制器的恢復(fù)路徑必須是唯一的。如果一個(gè)容器視圖控制器有兩個(gè)子視圖,容器必須為每個(gè)子視圖控制器分配一個(gè)獨(dú)特的恢復(fù)標(biāo)示符。一些UIKit中容器視圖控制器會自動消除歧義子視圖控制器,允許為每個(gè)子視圖控制器使用相同恢復(fù)標(biāo)示符。例如,類根據(jù)每個(gè)子視圖控制器在導(dǎo)航堆棧中的位置添加信息。關(guān)于一個(gè)給定視圖控制器的行為更多信息,參見相應(yīng)的類引用。

如何使用恢復(fù)標(biāo)示符和恢復(fù)路徑創(chuàng)建視圖控制器的更多信息,參見啟動時(shí)恢復(fù)視圖控制器(Restoring View Controllers at Launch Time)。

不包括視圖控制器組

在恢復(fù)過程中不包括整個(gè)視圖控制器組,設(shè)置父視圖控制器的恢復(fù)標(biāo)示符為nil。圖7-1展示了設(shè)置恢復(fù)標(biāo)示符為nil對視圖層級結(jié)構(gòu)的影響。缺少保存數(shù)據(jù),在稍后無法恢復(fù)視圖控制器。

圖7-1 自動保存過程中不包括的視圖控制器

在隨后的恢復(fù)過程中,并不完全刪除其中不包括的一個(gè)或多個(gè)視圖控制器。在啟動時(shí),任何視圖控制器都是應(yīng)用的一部分,默認(rèn)創(chuàng)建設(shè)置,如圖7-2所示。按照默認(rèn)配置創(chuàng)建視圖控制器。

圖7-2 加載默認(rèn)視圖控制器組

自動保存過程中,可以手動保存不包括的視圖控制器。保存視圖控制器的引用即保存視圖控制器和其狀態(tài)信息。例如,如果圖7-1中的應(yīng)用代理保存導(dǎo)航控制器的三個(gè)子視圖控制器,他們的狀態(tài)將被保存下來。在恢復(fù)過程中,應(yīng)用代理可以重現(xiàn)創(chuàng)建這些視圖控制器并push他們到導(dǎo)航控制器的堆棧上。

保存視圖控制器的視圖

一些視圖有更多與視圖而不是父視圖控制器相關(guān)的狀態(tài)信息。例如,你希望保存滾動視圖的一個(gè)滾動位置。視圖控制器負(fù)責(zé)提供滾動視圖的內(nèi)容,而滾動視圖本身負(fù)責(zé)保存其視覺狀態(tài)。

保存視圖狀態(tài),執(zhí)行以下操作:

· 指定為 restoration Identifier 屬性一個(gè)有效的字符串。

· 使用具有有效標(biāo)示符的視圖控制器的視圖。

· 對于表視圖和集合視圖,指定采用UI Data Source Model Association 協(xié)議的數(shù)據(jù)源

將標(biāo)示符分配給視圖告訴UIKit應(yīng)該保存視圖狀態(tài)。當(dāng)稍后恢復(fù)視圖控制器,UIKit也恢復(fù)有恢復(fù)標(biāo)示符的視圖的狀態(tài)。

在啟動時(shí)恢復(fù)視圖控制器

在啟動時(shí),UIKit試圖恢復(fù)你的應(yīng)用到之前的狀態(tài)。那時(shí),UIKit訪問你的應(yīng)用創(chuàng)建(或確定)用戶界面保存的視圖控制器對象。當(dāng)定位視圖控制器時(shí),UIKit按照以下順序搜索:

  1. **如果視圖控制器有一個(gè)恢復(fù)類,UIKit訪問該類提供視圖控制器。UIKit調(diào)用恢復(fù)類的 [viewControllerWithRestorationIdentifierPath:coder:](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIViewControllerRestoration_protocol/index.html#//apple_ref/occ/intfcm/UIViewControllerRestoration/viewControllerWithRestorationIdentifierPath:coder:) 方法來檢索視圖控制器。**如果該方法返回nil,則假設(shè)應(yīng)用并不希望重新創(chuàng)建視圖控制器,UIKit停止尋找該視圖控制器。
    
  2. **如果視圖控制器沒有恢復(fù)類,UIKit要求應(yīng)用代理提供視圖控制器。**UIKit調(diào)用應(yīng)用代理的[application:viewControllerWithRestorationIdentifierPath:coder:](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:viewControllerWithRestorationIdentifierPath:coder:)方法尋找沒有恢復(fù)類的視圖控制器。如果該方法返回nil,UIKit嘗試找到隱藏的視圖控制器。
    
  3. **如果有正確恢復(fù)路徑的視圖控制器已經(jīng)存在,UIKit使用該對象。**如果你的應(yīng)用在啟動時(shí)(無論是以編程的方式還是通過storyboard加載的方式)創(chuàng)建視圖控制器,并且這些視圖控制器有恢復(fù)標(biāo)識符,UIKit基于他們的恢復(fù)路徑隱式的查找他們。
    
  4. **如果視圖控制器最初是從storyboard文件加載,UIKit使用保存的storyboard信息來定位并創(chuàng)建它。**UIKit保存視圖控制器的storyboard信息到恢復(fù)文件中。在恢復(fù)時(shí),UIKit使用這些信息來定位相同的storyboard文件,如果通過其他任何方式?jīng)]有找到視圖控制器,則實(shí)例化相應(yīng)視圖控制器。
    

將恢復(fù)類分配給視圖控制器可以防止UIKit隱式的搜索該視圖控制器。使用恢復(fù)類讓你可以控制是否真正創(chuàng)建一個(gè)視圖控制器。例如,如果你的類決定不再重新創(chuàng)建視圖控制器,viewControllerWithRestorationIdentifierPath:coder:方法可以返回nil。當(dāng)不存在恢復(fù)類,UIKit會盡可能找到或者創(chuàng)建該視圖控制器來恢復(fù)它。

當(dāng)使用一個(gè)恢復(fù)類,viewControllerWithRestorationIdentifierPath:coder: 方法應(yīng)該創(chuàng)建該類的新實(shí)例,執(zhí)行初始化,并返回結(jié)果對象。列表7-1 展示了如何使用此方法從storyboard中加載視圖控制器的例子。因?yàn)樵撘晥D控制器最初從storyboard加載,該方法使用UIStateRestorationViewControllerStoryboardKey key從文件中找到storyboard。注意:該方法不配置視圖控制器的數(shù)據(jù)字段。當(dāng)解碼視圖控制器的狀態(tài)時(shí),發(fā)生這一步。

列表7-1 在恢復(fù)過程中創(chuàng)建一個(gè)新視圖控制器

<pre><code>
+(UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *) identifierComponents coder:(NSCoder *)coder {

MyViewController* vc;
UIStoryboard* sb = [coder decodeObjectForKey UIStateRestorationViewControllerStoryboardKey];
if (sb) {
    vc = (PushViewController*)[sb instantiateViewControllerWithIdentifier:@"MyViewController"];
    vc.restorationIdentifier = [identifierComponents lastObject];
    vc.restorationClass = [MyViewController class];
}
return vc;

}
</pre></code>

當(dāng)手動重新創(chuàng)建視圖控制器,重新分配恢復(fù)標(biāo)識符和恢復(fù)類是個(gè)好習(xí)慣。恢復(fù)恢復(fù)標(biāo)識符的最簡單的方法是獲取identifierComponents 數(shù)組中的最后一項(xiàng),并將其分配給你的視圖控制器。

在啟動時(shí)由應(yīng)用主要storyboard文件中創(chuàng)建的對象,不需要為每個(gè)對象創(chuàng)建新實(shí)例。讓UIKit隱式的查找這些對象或者使用應(yīng)用代理的application:viewControllerWithRestorationIdentifierPath:coder:方法查找這些存在的對象。

編碼和解碼視圖控制器狀態(tài)

對于每個(gè)要保留的對象,UIKit調(diào)用對象的encodeRestorableStateWithCoder:方法來保存其狀態(tài)。在恢復(fù)過程中,UIKit調(diào)用對應(yīng)的decodeRestorableStateWithCoder: 方法來解碼該狀態(tài)并將其用于該對象。這些方法的實(shí)現(xiàn)是可選的,但是建議,實(shí)現(xiàn)。你可能使用它們來保存和恢復(fù)以下類型的信息:

· 顯示數(shù)據(jù)的引用(不是數(shù)據(jù)本身)

· 對于容器視圖控制器,其子視圖控制器的引用

· 當(dāng)前選擇的信息

· 對于用戶可配置視圖的視圖控制器,當(dāng)前配置視圖的信息

在你的編碼和解碼方法中,你可以編碼對象和編碼器支持的任何數(shù)據(jù)類型。除了視圖和視圖控制器的其他所有對象必須采用 NSCoding協(xié)議并使用協(xié)議中的方法來保存其狀態(tài)。對于視圖和視圖控制器,編碼器不使用 NSCoding協(xié)議來保存對象狀態(tài)。相反,編碼器保存該對象的恢復(fù)標(biāo)識符并將其添加到保存對象列表,這將導(dǎo)致該對象的encodeRestorableStateWithCoder: 方法被調(diào)用。

視圖控制器的encodeRestorableStateWithCoder:decodeRestorableStateWithCoder:方法必須在實(shí)現(xiàn)的某個(gè)位置調(diào)用super方法。調(diào)用super方法讓父類有機(jī)會保存和恢復(fù)任何額外的信息。列表7-2展示了這些方法的實(shí)現(xiàn)例子,該方法保存一個(gè)數(shù)值用于識別指定視圖控制器。

列表7-2 編碼和界面視圖控制器狀態(tài)

<pre><code>
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder {

[super encodeRestorableStateWithCoder:coder];
[coder encodeInt:self.number forKey:MyViewControllerNumber];

}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
self.number = [coder decodeIntForKey:MyViewControllerNumber];
}
</pre></code>

在編碼和解碼過程中,編碼對象不共享。每個(gè)保存狀態(tài)的對象接收自己的編碼對象。使用獨(dú)特的編碼器表明你不用擔(dān)心key之間的命名沖突。然而,不要使用UIApplicationStateRestorationBundleVersionKey,UIApplicationStateRestorationUserInterfaceIdiomKeyUIStateRestorationViewControllerStoryboardKey key來命名。UIKit使用這些key來存儲視圖控制器狀態(tài)的額外信息。

關(guān)于視圖控制器編碼解碼方法的更多信息,參見UIViewcontroller類引用(UIViewController Class Reference)。

保存和恢復(fù)視圖控制器技巧

在視圖控制器中添加狀態(tài)保存與恢復(fù),考慮以下指南:

· 請記住可能不希望保存所有視圖控制器。在某些情況下,保存某個(gè)視圖控制器沒有意義。例如,如果應(yīng)用顯示一個(gè)變更,你希望取消操作并恢復(fù)到應(yīng)用的前一個(gè)界面。在這種情況下,你不用保存該視圖控制器。

· 恢復(fù)過程中避免交換視圖控制器類。狀態(tài)保存系統(tǒng)為其保存的視圖控制器類編碼。在恢復(fù)期間,如果你的應(yīng)用返回一個(gè)不匹配原始對象(或不是原始對象的子類)的對象,系統(tǒng)不要求視圖控制器解碼任何狀態(tài)信息。因此,劃掉舊的視圖控制器換成完全不同的視圖控制器,這個(gè)過程不恢復(fù)該對象的全部狀態(tài)。

· 狀態(tài)保存系統(tǒng)希望你有意的使用視圖控制器。恢復(fù)過程依賴視圖控制器的控制關(guān)系來重建你的界面。如果你沒有正確使用容器視圖控制器,保存系統(tǒng)不能找到你的視圖控制器。例如,除非相應(yīng)的視圖控制器之間包含某種關(guān)系,否則不要在不同的視圖中嵌入一個(gè)視圖控制器的視圖。

官方原文地址:

https://developer.apple.com/library/prerelease/ios/featuredarticles/ViewControllerPGforiPhoneOS/PreservingandRestoringState.html#//apple_ref/doc/uid/TP40007457-CH28-SW1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,427評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,380評論 2 379

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