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

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

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

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

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

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

保存和恢復(fù)的過(guò)程的概述删窒,參見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í)站宗,在視圖層級(jí)結(jié)構(gòu)中的所有的父視圖控制器必須有恢復(fù)標(biāo)示符。在保存過(guò)程中益愈,UIKit從窗口的根視圖控制器開始并遍歷視圖控制器層級(jí)結(jié)構(gòu)梢灭。如果該層級(jí)結(jié)構(gòu)中一個(gè)視圖控制器沒有恢復(fù)標(biāo)示符,該視圖控制器和其所有子視圖控制器和present的視圖控制器都會(huì)被忽略蒸其。

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

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

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

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

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

不包括視圖控制器組

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

圖7-1 自動(dòng)保存過(guò)程中不包括的視圖控制器

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

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

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

保存視圖控制器的視圖

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

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

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

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

· 對(duì)于表視圖和集合視圖捆憎,指定采用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)躲惰。

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

在啟動(dòng)時(shí),UIKit試圖恢復(fù)你的應(yīng)用到之前的狀態(tài)变抽。那時(shí)础拨,UIKit訪問你的應(yīng)用創(chuàng)建(或確定)用戶界面保存的視圖控制器對(duì)象氮块。當(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:) 方法來(lái)檢索視圖控制器。**如果該方法返回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使用該對(duì)象肮韧。**如果你的應(yīng)用在啟動(dòng)時(shí)(無(wú)論是以編程的方式還是通過(guò)storyboard加載的方式)創(chuàng)建視圖控制器融蹂,并且這些視圖控制器有恢復(fù)標(biāo)識(shí)符,UIKit基于他們的恢復(fù)路徑隱式的查找他們弄企。
    
  4. **如果視圖控制器最初是從storyboard文件加載超燃,UIKit使用保存的storyboard信息來(lái)定位并創(chuàng)建它。**UIKit保存視圖控制器的storyboard信息到恢復(fù)文件中拘领。在恢復(fù)時(shí)意乓,UIKit使用這些信息來(lái)定位相同的storyboard文件,如果通過(guò)其他任何方式?jīng)]有找到視圖控制器约素,則實(shí)例化相應(yīng)視圖控制器届良。
    

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

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

列表7-1 在恢復(fù)過(guò)程中創(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)手動(dòng)重新創(chuàng)建視圖控制器罐韩,重新分配恢復(fù)標(biāo)識(shí)符和恢復(fù)類是個(gè)好習(xí)慣憾赁。恢復(fù)恢復(fù)標(biāo)識(shí)符的最簡(jiǎn)單的方法是獲取identifierComponents 數(shù)組中的最后一項(xiàng)散吵,并將其分配給你的視圖控制器龙考。

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

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

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

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

· 對(duì)于容器視圖控制器股囊,其子視圖控制器的引用

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

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

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

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

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

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

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

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

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

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

· 狀態(tài)保存系統(tǒng)希望你有意的使用視圖控制器验烧。恢復(fù)過(guò)程依賴視圖控制器的控制關(guān)系來(lái)重建你的界面又跛。如果你沒有正確使用容器視圖控制器碍拆,保存系統(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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末礼烈,一起剝皮案震驚了整個(gè)濱河市弧满,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌此熬,老刑警劉巖庭呜,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異犀忱,居然都是意外死亡募谎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門阴汇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)数冬,“玉大人,你說(shuō)我怎么就攤上這事搀庶〖矗” “怎么了疯淫?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)戳玫。 經(jīng)常有香客問我熙掺,道長(zhǎng),這世上最難降的妖魔是什么咕宿? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任币绩,我火速辦了婚禮,結(jié)果婚禮上府阀,老公的妹妹穿的比我還像新娘缆镣。我一直安慰自己,他們只是感情好试浙,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布董瞻。 她就那樣靜靜地躺著,像睡著了一般田巴。 火紅的嫁衣襯著肌膚如雪钠糊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天壹哺,我揣著相機(jī)與錄音抄伍,去河邊找鬼。 笑死管宵,一個(gè)胖子當(dāng)著我的面吹牛截珍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播箩朴,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼岗喉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了炸庞?” 一聲冷哼從身側(cè)響起钱床,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎燕雁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鲸拥,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拐格,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刑赶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捏浊。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撞叨,靈堂內(nèi)的尸體忽然破棺而出金踪,到底是詐尸還是另有隱情浊洞,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布胡岔,位于F島的核電站法希,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏靶瘸。R本人自食惡果不足惜苫亦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怨咪。 院中可真熱鬧屋剑,春花似錦、人聲如沸诗眨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)匠楚。三九已至巍膘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間油啤,已是汗流浹背典徘。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留益咬,地道東北人逮诲。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像幽告,于是被迫代替她去往敵國(guó)和親梅鹦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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