ViewController編程指南定義-保存和恢復狀態(tài)

視圖控制器在狀態(tài)保存和恢復過程中起重要作用。 狀態(tài)保留記錄您的應用程序在暫停之前的配置,以便可以在后續(xù)應用程序啟動時恢復配置。 將應用程序恢復到其先前的配置可為用戶節(jié)省時間,并提供更好的用戶體驗。

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

  • (必需)將恢復標識符分配給要保留其配置的視圖控制器;
  • (必需)告訴iOS如何在啟動時創(chuàng)建或定位新的視圖控制器對象;
  • (可選)對于每個視圖控制器,存儲將該視圖控制器返回到其原始配置所需的任何特定配置數(shù)據(jù);

標記視圖控制器以進行保存

UIKit僅保留您要讓它保留的視圖控制器。 每個視圖控制器都有一個restorationIdentifier屬性,默認值為nil。 將該屬性設(shè)置為有效字符串會告訴UIKit應保留視圖控制器及其視圖。 您可以以編程方式或在故事板文件中分配恢復標識符。

當分配恢復標識符時,請記住視圖控制器層次結(jié)構(gòu)中的所有父視圖控制器也必須具有恢復標識符。 在保存過程中,UIKit從窗口的根視圖控制器開始,并遍歷視圖控制器層次結(jié)構(gòu)。 如果該層次結(jié)構(gòu)中的視圖控制器不具有恢復標識符,則忽略視圖控制器及其所有子視圖控制器和呈現(xiàn)的視圖控制器。

選擇有效恢復標識符

UIKit使用您的恢復標識符字符串以后重新創(chuàng)建視圖控制器,因此選擇可以容易地識別您的代碼的字符串。 如果UIKit無法自動創(chuàng)建一個視圖控制器,它會要求您創(chuàng)建它,為您提供視圖控制器及其所有父視圖控制器的恢復標識符。 這個標識符鏈表示視圖控制器的恢復路徑,是你如何確定請求哪個視圖控制器。 恢復路徑在根視圖控制器處開始,并且包括直到并且包括所請求的視圖控制器的每個視圖控制器。

恢復標識符通常只是視圖控制器的類名。 如果在許多地方使用相同的類,則可能需要分配更有意義的值。 例如,您可以基于由視圖控制器管理的數(shù)據(jù)分配字符串。

每個視圖控制器的恢復路徑必須是唯一的。 如果容器視圖控制器有兩個子節(jié)點,則容器必須為每個子節(jié)點分配唯一的恢復標識符。 UIKit中的一些容器視圖控制器自動消除其子視圖控制器的歧義,允許您為每個子項使用相同的恢復標識符。 例如,UINavigationController類根據(jù)其在導航堆棧中的位置向每個子項添加信息。

不包括視圖控制器組

要從恢復過程中排除整個視圖控制器組,請將父視圖控制器的恢復標識符設(shè)置為nil。 圖7-1顯示了將恢復標識符設(shè)置為nil對視圖控制器層次結(jié)構(gòu)的影響。 缺少保留數(shù)據(jù)阻止了視圖控制器以后被恢復。

圖7-1從自動保存過程中排除視圖控制器

state_vc_caveats_2x.png

排除一個或多個視圖控制器在后續(xù)還原期間不會完全刪除它們。 在啟動時,仍然創(chuàng)建作為應用程序默認設(shè)置的一部分的任何視圖控制器,如圖7-2所示。 這樣的視圖控制器以其默認配置重新創(chuàng)建,但仍然創(chuàng)建它們。

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

state_vc_caveats_2_2x.png

從自動保存過程中排除視圖控制器不會阻止您手動保留它。 在恢復歸檔中保存對視圖控制器的引用會保留視圖控制器及其狀態(tài)信息。 例如,如果圖7-1中的應用程序委托保存了導航控制器的三個子代,則它們的狀態(tài)將被保留。 在恢復期間,應用程序代理可以重新創(chuàng)建這些視圖控制器并將它們推送到導航控制器的堆棧。

保留視圖控制器的視圖

一些視圖具有與視圖相關(guān)但與父視圖控制器無關(guān)的附加狀態(tài)信息。 例如,滾動視圖具有您可能希望保留的滾動位置。 雖然視圖控制器負責提供滾動視圖的內(nèi)容,但是滾動視圖本身負責保持其可視狀態(tài)。

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

  • 為視圖的restoredIdentifier屬性分配一個有效的字符串。
  • 使用來自還具有有效恢復標識符的視圖控制器的視圖。
  • 對于表視圖和集合視圖,請分配采用UIDataSourceModelAssociation協(xié)議的數(shù)據(jù)源。

為視圖分配恢復標識符告訴UIKit它應該將該視圖的狀態(tài)寫入保留存檔。 當視圖控制器以后恢復時,UIKit還恢復具有恢復標識符的任何視圖的狀態(tài)。

在啟動時恢復視圖控制器

在啟動時,UIKit嘗試將您的應用恢復到之前的狀態(tài)。 當時,UIKit要求您的應用程序創(chuàng)建(或定位)包含保留的用戶界面的視圖控制器對象。 UIKit在嘗試查找視圖控制器時按以下順序進行搜索:

  1. 如果視圖控制器有一個恢復類,UIKit要求該類提供視圖控制器。 UIKit調(diào)用關(guān)聯(lián)的恢復類的viewControllerWithRestorationIdentifierPath:coder:方法來檢索視圖控制器。 如果該方法返回nil,則假定應用程序不想重新創(chuàng)建視圖控制器,UIKit停止查找它。
  2. 如果視圖控制器沒有恢復類,UIKit要求應用程序代理提供視圖控制器。 UIKit調(diào)用應用程序:viewControllerWithRestorationIdentifierPath:coder:您的應用程序委托的方法來查找沒有恢復類的視圖控制器。 如果該方法返回nil,UIKit試圖隱式地查找視圖控制器。
  3. 如果具有正確恢復路徑的視圖控制器已存在,UIKit將使用該對象。 如果您的應用程序在啟動時創(chuàng)建視圖控制器(以編程方式或通過故事板加載它們),并且這些視圖控制器有恢復標識符,UIKit隱式地基于它們的恢復路徑找到它們。
  4. 如果視圖控制器最初從故事板文件加載,UIKit使用保存的故事板信息來定位和創(chuàng)建它。 UIKit將有關(guān)視圖控制器的storyboard的信息保存在恢復存檔中。 在恢復時,UIKit使用該信息來定位相同的故事板文件,并且如果沒有通過任何其他方式找到視圖控制器,則實例化相應的視圖控制器。

向視圖控制器分配恢復類可以防止UIKit隱含地搜索該視圖控制器。 使用恢復類可以更好地控制是否要創(chuàng)建視圖控制器。 例如,如果您的類確定不應重新創(chuàng)建視圖控制器,則您的viewControllerWithRestorationIdentifierPath:coder:方法可以返回nil。 當沒有恢復類時,UIKit將盡其所能找到或創(chuàng)建視圖控制器并恢復它。

當使用恢復類時,您的viewControllerWithRestorationIdentifierPath:coder:方法應該創(chuàng)建一個類的新實例,執(zhí)行最小初始化,并返回結(jié)果對象。 清單7-1顯示了如何使用此方法從故事板加載視圖控制器的示例。 因為視圖控制器最初從故事板加載,所以此方法使用UIStateRestorationViewControllerStoryboardKey鍵從歸檔中獲取故事板。 請注意,此方法不會嘗試配置視圖控制器的數(shù)據(jù)字段。 該步驟稍后發(fā)生在視圖控制器的狀態(tài)被解碼時。

清單7-1在恢復期間創(chuàng)建一個新的視圖控制器

+ (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;
}

重新分配恢復標識符和恢復類是手動重新創(chuàng)建視圖控制器時采用的好習慣。 恢復恢復標識符的最簡單的方法是抓取identifierComponents數(shù)組中的最后一個項目,并將其分配給視圖控制器。

對于在啟動時從應用程序的主storyboard文件創(chuàng)建的對象,請不要創(chuàng)建每個對象的新實例。 讓UIKit隱式找到這些對象或使用應用程序:viewControllerWithRestorationIdentifierPath:coder:您的應用程序委托的方法來查找現(xiàn)有對象。

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

對于每個要保存的對象,UIKit調(diào)用對象的encodeRestorableStateWithCoder:方法給它一個保存其狀態(tài)的機會。 在恢復過程中,UIKit調(diào)用匹配的decodeRestorableStateWithCoder:方法來解碼該狀態(tài)并將其應用于對象。 這些方法的實現(xiàn)是可選的,但建議為您的視圖控制器。 您可以使用它們來保存和恢復以下類型的信息:

  • 對任何正在顯示的數(shù)據(jù)的引用(不是數(shù)據(jù)本身)
  • 對于容器視圖控制器,引用其子視圖控制器
  • 有關(guān)當前選擇的信息
  • 對于具有用戶可配置視圖的視圖控制器,有關(guān)該視圖的當前配置的信息。

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

你的視圖控制器的encodeRestorableStateWithCoder:和decodeRestorableStateWithCoder:方法必須在其實現(xiàn)的某個點調(diào)用super。 調(diào)用super給父類一個機會來保存和恢復任何附加信息。 清單7-2顯示了保存用于標識指定視圖控制器的數(shù)值的這些方法的示例實現(xiàn)。

代碼7-2對視圖控制器的狀態(tài)進行編碼和解碼。

- (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];
}

編碼器對象在編碼和解碼過程中不共享。 每個具有可保存狀態(tài)的對象接收其自己的編碼器對象。 使用唯一的編碼器意味著你不必擔心你的鍵之間的命名空間沖突。 但是,不要使用UIApplicationStateRestorationBundleVersionKey,UIApplicationStateRestorationUserInterfaceIdiomKey和UIStateRestorationViewControllerStoryboardKey鍵名稱自己。 UIKit使用這些鍵來存儲有關(guān)視圖控制器狀態(tài)的附加信息。

保存和恢復視圖控制器的提示

當您在視圖控制器中添加對狀態(tài)保存和恢復的支持時,請考慮以下準則:

  • 請記住,您可能不想保留所有視圖控制器。 在某些情況下,保留視圖控制器可能沒有意義。 例如,如果應用程序正在顯示更改,則可能需要取消操作并將應用程序恢復到上一屏幕。 在這種情況下,您不會保留要求新密碼信息的視圖控制器。
  • 避免在恢復過程中交換視圖控制器類。 狀態(tài)保存系統(tǒng)對它保存的視圖控制器的類進行編碼。 在恢復期間,如果您的應用程序返回其類與原始對象不匹配(或不是其子類)的對象,則系統(tǒng)不會要求視圖控制器解碼任何狀態(tài)信息。 因此,換出完全不同的舊視圖控制器不會恢復對象的完整狀態(tài)。
  • 狀態(tài)保留系統(tǒng)期望您使用它們的意圖的視圖控制器。 恢復過程依賴于視圖控制器的包含關(guān)系來重建接口。 如果不正確使用容器視圖控制器,保存系統(tǒng)將無法找到您的視圖控制器。 例如,從不將視圖控制器的視圖嵌入在不同的視圖中,除非在相應的視圖控制器之間存在包含關(guān)系。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

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