iOS UI狀態(tài)保存和恢復(一)

級別: ★★☆☆☆
標簽:「iOS」「UIStateRestoration」
作者: 沐靈洛
審校: QiShare團隊


前言:iOS 開發(fā)中,我們都知道一個App點擊了home按鍵或者切換至其他應用時,將進入后臺。隨著時間的推移资柔,App會經歷后臺運行,后臺懸掛撵割,最后被殺死贿堰。假如有這樣一個場景:

場景1:用戶正在使用我們App進行個人信息的編輯,突然接到了一個電話啡彬,使得App進入后臺并且通話時間超過了App后臺备耄活的時間。當用戶通話完畢的時候庶灿,返回繼續(xù)填寫纵搁,卻發(fā)現App重新啟動了,并且用戶之前填寫的數據往踢,都沒有保存腾誉,需要重新輸入?用戶的體驗會很不好峻呕。

對于此問題利职,我們可能會說讓App后臺保持活躍不就行啦。是的山上,這是個很好的解決方案眼耀。但是除了這個方案,我們是不是有其他的辦法實現UI界面和數據的保存和恢復佩憾。答案是肯定的哮伟,接下來我們會介紹一種方案UIStateRestoration

一妄帘、關于UIStateRestoration

UIStateRestoration出現于iOS 6.0以后的API中楞黄。主要幫助我們實現特定場景下的UI保存和恢復。UIStateRestoration是一個協(xié)議類抡驼,在蘋果的系統(tǒng)中UIKit框架下的UIApplication鬼廓、UIViewController、UIView都實現了UIStateRestoration協(xié)議致盟。

關于UI狀態(tài)從應用程序啟動到恢復以及UI狀態(tài)保存時相關API的調用順序碎税,用官網的圖解大家可以理解的更清楚尤慰。

UI狀態(tài)從應用程序啟動到恢復調用順序說明
UI狀態(tài)保存時調用順序說明

UI狀態(tài)恢復,只有當AppDelegate實現application:shouldRestoreApplicationState:并且在方法中返回true時才會生效雷蹂。
UI狀態(tài)保存伟端,只有當AppDelegate實現application: shouldSaveApplicationState:并且在方法中返回true時才會生效。

二匪煌、UIStateRestoration的介紹

  1. 系統(tǒng)進行UI狀態(tài)的保存和恢復時责蝠,自動使用以下常量字符串,進行相關數據的歸檔萎庭。
#pragma mark -- State Restoration Coder Keys --
// UIStoryBoard that originally created the ViewController that saved state, nil if no UIStoryboard
//保存和創(chuàng)建一個故事版用到的key
UIKIT_EXTERN NSString *const UIStateRestorationViewControllerStoryboardKey NS_AVAILABLE_IOS(6_0);
// NSString with value of info.plist's Bundle Version (app version) when state was last saved for the app
//應用程序上次狀態(tài)保存時info.plist的應用程序版本
UIKIT_EXTERN NSString *const UIApplicationStateRestorationBundleVersionKey NS_AVAILABLE_IOS(6_0);
// NSNumber containing the UIUserInterfaceIdiom enum value of the app that saved state
//狀態(tài)保存時應用程序的`UIUserInterfaceIdiom`枚舉值
UIKIT_EXTERN NSString *const UIApplicationStateRestorationUserInterfaceIdiomKey NS_AVAILABLE_IOS(6_0);
// NSDate specifying the date/time the state restoration archive was saved. This is in UTC.
//狀態(tài)保存的時間霜医,UTC格式。
UIKIT_EXTERN NSString *const UIApplicationStateRestorationTimestampKey NS_AVAILABLE_IOS(7_0);
// NSString with value of the system version (iOS version) when state was last saved for the app
//上次應用程序保存狀態(tài)時的系統(tǒng)版本(iOS版本)
UIKIT_EXTERN NSString *const UIApplicationStateRestorationSystemVersionKey NS_AVAILABLE_IOS(7_0);
  1. UIViewControllerRestoration協(xié)議:在UI狀態(tài)恢復時幫我們生成一個控制器驳规。
#pragma mark -- State Restoration protocols for UIView and UIViewController --
// A class must implement this protocol if it is specified as the restoration class of a UIViewController.
//如果將類指定為UIViewController的恢復類肴敛,則必須實現此協(xié)議。
@protocol UIViewControllerRestoration
+ (nullable UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder;
@end
  1. UIDataSourceModelAssociation協(xié)議:目前只有UITableView and UICollectionView實現了這個協(xié)議达舒。
    官網說明: UIDataSourceModelAssociation.
@protocol UIDataSourceModelAssociation
- (nullable NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view;
- (nullable NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view;
@end
  1. UIStateRestoring協(xié)議:實現UIStateRestoring協(xié)議值朋,可以讓我們自定義的視圖(非UIView和UIViewController子類)加入狀態(tài)恢復。前提必須使用UIApplication的+ (void)registerObjectForStateRestoration:(id<UIStateRestoring>)object restorationIdentifier:(NSString *)restorationIdentifier方法注冊巩搏。
+ (void)registerObjectForStateRestoration:(id<UIStateRestoring>)object restorationIdentifier:(NSString *)restorationIdentifier
@protocol UIObjectRestoration;
// Conform to this protocol if you want your objects to participate in state restoration. 
// To participate in state restoration, the function registerObjectForStateRestoration must
// be called for the object.
/*如果您希望對象參與狀態(tài)恢復,請遵守此協(xié)議趾代。
要參與狀態(tài)恢復贯底,函數registerObjectForStateRestoration必須為此對象而調用。*/
@protocol UIStateRestoring <NSObject>
@optional
// The parent property is used to scope the restoration identifier path for an object, to
// disambiguate it from other objects that might be using the same identifier. The parent
// must be a restorable object or a view controller, else it will be ignored.
/*parent屬性用于定義一個對象的恢復標識恢復路徑撒强,以便從可能使用相同恢復標識的其他對象中消除歧義禽捆。
parent屬性必須是可恢復對象`id<UIStateRestoring> `或視圖控制器,否則將被忽略飘哨。
個人理解:類似繼承體系模式胚想,方便歸整清楚恢復的路徑,幫助我們進行一定順序和層次的恢復芽隆。*/
@property (nonatomic, readonly, nullable) id<UIStateRestoring> restorationParent;
// The restoration class specifies a class which is consulted during restoration to find/create
// the object, rather than trying to look it up implicitly
/*
objectRestorationClass指定在恢復期間用于查找和創(chuàng)建需要恢復的對象的類浊服。
并不是試圖隱式查找和創(chuàng)建需要恢復的對象
*/
@property (nonatomic, readonly, nullable) Class<UIObjectRestoration> objectRestorationClass;
// Methods to save and restore state for the object. If these aren't implemented, the object
// can still be referenced by other objects in state restoration archives, but it won't
// save/restore any state of its own.
/*
保存和恢復對象狀態(tài)的方法。
如果沒有實現這些方法胚吁,對象仍可以被狀態(tài)恢復歸檔中的其他對象引用牙躺,但它將不會保存和恢復自己的任何狀態(tài)。
*/
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder;
- (void) decodeRestorableStateWithCoder:(NSCoder *)coder;
// applicationFinishedRestoringState is called on all restored objects that implement the method *after* all other object
// decoding has been done (including the application delegate). This allows an object to complete setup after state
// restoration, knowing that all objects from the restoration archive have decoded their state.
/*在所有其他對象實現恢復方法腕扶,解碼完成(包括`AppDelegate`的解碼)并恢復了所有的可恢復對象后才會調用applicationFinishedRestoringState孽拷。
這允許對象在狀態(tài)恢復之后完成設置,可以通過此方法明確知道恢復檔案中的所有對象都已解碼其狀態(tài)
*/
- (void) applicationFinishedRestoringState;
@end
// Protocol for classes that act as a factory to find a restorable object during state restoration
// A class must implement this protocol if it is specified as the restoration class of a UIRestorableObject.
//作為工廠類的協(xié)議半抱,用于在狀態(tài)恢復期間查找可恢復對象脓恕。如果指定某個類為`id<UIStateRestoring>`的`objectRestorationClass `膜宋,則該類必須實現此協(xié)議。
@protocol UIObjectRestoration
+ (nullable id<UIStateRestoring>) objectWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder;
@end

UIStateRestoration場景

適用于App進入后臺炼幔,后臺停留時間超過系統(tǒng)分配的后臺活躍時間后被系統(tǒng)殺死時的場景秋茫。因為當用戶強制退出應用程序時,系統(tǒng)會自動刪除應用程序的保留狀態(tài)江掩。在應用程序被終止時刪除保留的狀態(tài)信息是一項安全預防措施学辱。如果應用程序在啟動時崩潰,系統(tǒng)也會刪除保留狀態(tài)作為類似的安全預防措施环形。

UIStateRestoration調試

根據場景描述策泣,如果要測試應用程序恢復其狀態(tài)的能力,則在調試期間不應使用多任務欄來強制終止應用程序抬吟∪荆可以通過設置項目的plist文件下Application does not run in background為YES。

UIApplication對于UIStateRestoration協(xié)議的實現接口
#pragma mark -- State Restoration protocol adopted by UIApplication delegate --
- (nullable UIViewController *) application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
UIViewController對于UIStateRestoration協(xié)議的實現接口
@interface UIViewController (UIStateRestoration) <UIStateRestoring>
@property (nullable, nonatomic, copy) NSString *restorationIdentifier NS_AVAILABLE_IOS(6_0);
@property (nullable, nonatomic, readwrite, assign) Class<UIViewControllerRestoration> restorationClass NS_AVAILABLE_IOS(6_0);
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) decodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) applicationFinishedRestoringState NS_AVAILABLE_IOS(7_0);
@end
UIView對于UIStateRestoration協(xié)議的實現接口
@interface UIView (UIStateRestoration)
@property (nullable, nonatomic, copy) NSString *restorationIdentifier NS_AVAILABLE_IOS(6_0);
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) decodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
@end

本篇我們介紹了UI狀態(tài)保存和恢復的流程火本,UIStateRestoration協(xié)議類的方法危队,適用場景,調試策略以及UIApplication钙畔、UIViewController茫陆、UIView關于1UIStateRestoration1協(xié)議所提供的接口方法。
下篇文章我們將介紹如何實現UI狀態(tài)保存和恢復擎析。


推薦文章:
Swift 運算符
iOS 中精確定時的常用方法
Sign In With Apple(一)
算法小專欄:動態(tài)規(guī)劃(一)
Dart基礎(一)
Dart基礎(二)
Dart基礎(三)
Dart基礎(四)
iOS 短信驗證碼倒計時按鈕

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末簿盅,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子揍魂,更是在濱河造成了極大的恐慌桨醋,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件现斋,死亡現場離奇詭異喜最,居然都是意外死亡,警方通過查閱死者的電腦和手機庄蹋,發(fā)現死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門瞬内,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蔓肯,你說我怎么就攤上這事遂鹊。” “怎么了蔗包?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵秉扑,是天一觀的道長。 經常有香客問我,道長舟陆,這世上最難降的妖魔是什么误澳? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮秦躯,結果婚禮上忆谓,老公的妹妹穿的比我還像新娘。我一直安慰自己踱承,他們只是感情好倡缠,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茎活,像睡著了一般昙沦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上载荔,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天盾饮,我揣著相機與錄音,去河邊找鬼懒熙。 笑死丘损,一個胖子當著我的面吹牛,可吹牛的內容都是我干的工扎。 我是一名探鬼主播徘钥,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肢娘!你這毒婦竟也來了吏饿?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蔬浙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贞远,有當地人在樹林里發(fā)現了一具尸體畴博,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年蓝仲,在試婚紗的時候發(fā)現自己被綠了俱病。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡袱结,死狀恐怖亮隙,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情垢夹,我是刑警寧澤溢吻,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響促王,放射性物質發(fā)生泄漏犀盟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一蝇狼、第九天 我趴在偏房一處隱蔽的房頂上張望阅畴。 院中可真熱鬧,春花似錦迅耘、人聲如沸贱枣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纽哥。三九已至,卻和暖如春血公,著一層夾襖步出監(jiān)牢的瞬間昵仅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工累魔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留摔笤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓垦写,卻偏偏與公主長得像吕世,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梯投,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容