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

視圖控制器在保存和恢復過程中起著非常重要的作用。狀態保存記錄應用中斷前的配置,在隨后應用啟動恢復配置。將應用恢復到先前的配置可以為用戶節省時間,并提供一個更好的用戶體驗。

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

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

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

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

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

標記保存視圖控制器

UIKit只保存你告訴它要保存的視圖控制器。每個視圖控制器有一個restorationIdentifier屬性,這個屬性的默認值為nil。設置這個屬性值為有效字符串,告訴UIKit視圖控制器和視圖應該要保存??梢砸跃幊痰姆绞交蛘咴趕toryboard文件中設置恢復標示符。

當分配恢復標示符時,在視圖層級結構中的所有的父視圖控制器必須有恢復標示符。在保存過程中,UIKit從窗口的根視圖控制器開始并遍歷視圖控制器層級結構。如果該層級結構中一個視圖控制器沒有恢復標示符,該視圖控制器和其所有子視圖控制器和present的視圖控制器都會被忽略。

選擇有效的恢復標示符

UIKit使用恢復標示符字符串在之后重新創建視圖控制器,所以必須選擇代碼容易識別的字符串。如果UIKit不能自動創建一個視圖控制器,要求你創建,UIKit會提供視圖控制器和其所有父視圖控制器的恢復標示符。這一串的標示符代表視圖控制器的恢復路徑,及如何決定哪些視圖控制器被請求?;謴吐窂綇母晥D控制器開始,包括呈現的每個視圖控制器和被請求的視圖控制器。

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

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

如何使用恢復標示符和恢復路徑創建視圖控制器的更多信息,參見啟動時恢復視圖控制器(Restoring View Controllers at Launch Time)。

不包括視圖控制器組

在恢復過程中不包括整個視圖控制器組,設置父視圖控制器的恢復標示符為nil。圖7-1展示了設置恢復標示符為nil對視圖層級結構的影響。缺少保存數據,在稍后無法恢復視圖控制器。

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

在隨后的恢復過程中,并不完全刪除其中不包括的一個或多個視圖控制器。在啟動時,任何視圖控制器都是應用的一部分,默認創建設置,如圖7-2所示。按照默認配置創建視圖控制器。

圖7-2 加載默認視圖控制器組

自動保存過程中,可以手動保存不包括的視圖控制器。保存視圖控制器的引用即保存視圖控制器和其狀態信息。例如,如果圖7-1中的應用代理保存導航控制器的三個子視圖控制器,他們的狀態將被保存下來。在恢復過程中,應用代理可以重現創建這些視圖控制器并push他們到導航控制器的堆棧上。

保存視圖控制器的視圖

一些視圖有更多與視圖而不是父視圖控制器相關的狀態信息。例如,你希望保存滾動視圖的一個滾動位置。視圖控制器負責提供滾動視圖的內容,而滾動視圖本身負責保存其視覺狀態。

保存視圖狀態,執行以下操作:

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

· 使用具有有效標示符的視圖控制器的視圖。

· 對于表視圖和集合視圖,指定采用UI Data Source Model Association 協議的數據源

將標示符分配給視圖告訴UIKit應該保存視圖狀態。當稍后恢復視圖控制器,UIKit也恢復有恢復標示符的視圖的狀態。

在啟動時恢復視圖控制器

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

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

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

當使用一個恢復類,viewControllerWithRestorationIdentifierPath:coder: 方法應該創建該類的新實例,執行初始化,并返回結果對象。列表7-1 展示了如何使用此方法從storyboard中加載視圖控制器的例子。因為該視圖控制器最初從storyboard加載,該方法使用UIStateRestorationViewControllerStoryboardKey key從文件中找到storyboard。注意:該方法不配置視圖控制器的數據字段。當解碼視圖控制器的狀態時,發生這一步。

列表7-1 在恢復過程中創建一個新視圖控制器

<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>

當手動重新創建視圖控制器,重新分配恢復標識符和恢復類是個好習慣。恢復恢復標識符的最簡單的方法是獲取identifierComponents 數組中的最后一項,并將其分配給你的視圖控制器。

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

編碼和解碼視圖控制器狀態

對于每個要保留的對象,UIKit調用對象的encodeRestorableStateWithCoder:方法來保存其狀態。在恢復過程中,UIKit調用對應的decodeRestorableStateWithCoder: 方法來解碼該狀態并將其用于該對象。這些方法的實現是可選的,但是建議,實現。你可能使用它們來保存和恢復以下類型的信息:

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

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

· 當前選擇的信息

· 對于用戶可配置視圖的視圖控制器,當前配置視圖的信息

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

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

列表7-2 編碼和界面視圖控制器狀態

<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>

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

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

保存和恢復視圖控制器技巧

在視圖控制器中添加狀態保存與恢復,考慮以下指南:

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

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

· 狀態保存系統希望你有意的使用視圖控制器?;謴瓦^程依賴視圖控制器的控制關系來重建你的界面。如果你沒有正確使用容器視圖控制器,保存系統不能找到你的視圖控制器。例如,除非相應的視圖控制器之間包含某種關系,否則不要在不同的視圖中嵌入一個視圖控制器的視圖。

官方原文地址:

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容