ViewController編程指南定義-保存和恢復狀態

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

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

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

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

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

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

選擇有效恢復標識符

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

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

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

不包括視圖控制器組

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

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

state_vc_caveats_2x.png

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

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

state_vc_caveats_2_2x.png

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

保留視圖控制器的視圖

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

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

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

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

在啟動時恢復視圖控制器

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 請記住,您可能不想保留所有視圖控制器。 在某些情況下,保留視圖控制器可能沒有意義。 例如,如果應用程序正在顯示更改,則可能需要取消操作并將應用程序恢復到上一屏幕。 在這種情況下,您不會保留要求新密碼信息的視圖控制器。
  • 避免在恢復過程中交換視圖控制器類。 狀態保存系統對它保存的視圖控制器的類進行編碼。 在恢復期間,如果您的應用程序返回其類與原始對象不匹配(或不是其子類)的對象,則系統不會要求視圖控制器解碼任何狀態信息。 因此,換出完全不同的舊視圖控制器不會恢復對象的完整狀態。
  • 狀態保留系統期望您使用它們的意圖的視圖控制器。 恢復過程依賴于視圖控制器的包含關系來重建接口。 如果不正確使用容器視圖控制器,保存系統將無法找到您的視圖控制器。 例如,從不將視圖控制器的視圖嵌入在不同的視圖中,除非在相應的視圖控制器之間存在包含關系。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容