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

級別: ★★☆☆☆
標籤:「iOS」「UIStateRestoration」
做者: 沐靈洛
審校: QiShare團隊php


前言:iOS 開發中,咱們都知道一個App點擊了home按鍵或者切換至其餘應用時,將進入後臺。隨着時間的推移,App會經歷後臺運行,後臺懸掛,最後被殺死。假若有這樣一個場景:git

場景1:用戶正在使用咱們App進行我的信息的編輯,忽然接到了一個電話,使得App進入後臺而且通話時間超過了App後臺保活的時間。當用戶通話完畢的時候,返回繼續填寫,卻發現App從新啓動了,而且用戶以前填寫的數據,都沒有保存,須要從新輸入?用戶的體驗會很很差。github

對於此問題,咱們可能會說讓App後臺保持活躍不就行啦。是的,這是個很好的解決方案。可是除了這個方案,咱們是否是有其餘的辦法實現UI界面和數據的保存和恢復。答案是確定的,接下來咱們會介紹一種方案UIStateRestoration算法

1、關於UIStateRestoration

UIStateRestoration出現於iOS 6.0之後的API中。主要幫助咱們實現特定場景下的UI保存和恢復。UIStateRestoration是一個協議類,在蘋果的系統中UIKit框架下的UIApplication、UIViewController、UIView都實現了UIStateRestoration協議。安全

關於UI狀態從應用程序啓動到恢復以及UI狀態保存時相關API的調用順序,用官網的圖解你們能夠理解的更清楚。bash

UI狀態從應用程序啓動到恢復調用順序說明

UI狀態保存時調用順序說明

UI狀態恢復,只有當AppDelegate實現application:shouldRestoreApplicationState:而且在方法中返回true時纔會生效。 UI狀態保存,只有當AppDelegate實現application: shouldSaveApplicationState:而且在方法中返回true時纔會生效。微信

2、UIStateRestoration的介紹

  1. 系統進行UI狀態的保存和恢復時,自動使用如下常量字符串,進行相關數據的歸檔。
#pragma mark -- State Restoration Coder Keys --
// UIStoryBoard that originally created the ViewController that saved state, nil if no UIStoryboard
//保存和建立一個故事版用到的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 //應用程序上次狀態保存時info.plist的應用程序版本 UIKIT_EXTERN NSString *const UIApplicationStateRestorationBundleVersionKey NS_AVAILABLE_IOS(6_0); // NSNumber containing the UIUserInterfaceIdiom enum value of the app that saved state //狀態保存時應用程序的`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. //狀態保存的時間,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 //上次應用程序保存狀態時的系統版本(iOS版本) UIKIT_EXTERN NSString *const UIApplicationStateRestorationSystemVersionKey NS_AVAILABLE_IOS(7_0); 複製代碼
  1. UIViewControllerRestoration協議:在UI狀態恢復時幫咱們生成一個控制器。
#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的恢復類,則必須實現此協議。
@protocol UIViewControllerRestoration
+ (nullable UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder;
@end
複製代碼
  1. UIDataSourceModelAssociation協議:目前只有UITableView and UICollectionView實現了這個協議。
    官網說明: UIDataSourceModelAssociation.
@protocol UIDataSourceModelAssociation
- (nullable NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view;
- (nullable NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view;
@end
複製代碼
  1. UIStateRestoring協議:實現UIStateRestoring協議,可讓咱們自定義的視圖(非UIView和UIViewController子類)加入狀態恢復。前提必須使用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.
/*若是您但願對象參與狀態恢復,請遵照此協議。
要參與狀態恢復,函數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指定在恢復期間用於查找和建立須要恢復的對象的類。
並非試圖隱式查找和建立須要恢復的對象
*/
@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.
/*
保存和恢復對象狀態的方法。
若是沒有實現這些方法,對象仍能夠被狀態恢復歸檔中的其餘對象引用,但它將不會保存和恢復本身的任何狀態。
*/
- (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。
這容許對象在狀態恢復以後完成設置,能夠經過此方法明確知道恢復檔案中的全部對象都已解碼其狀態
*/
- (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.
//做爲工廠類的協議,用於在狀態恢復期間查找可恢復對象。若是指定某個類爲`id<UIStateRestoring>`的`objectRestorationClass `,則該類必須實現此協議。
@protocol UIObjectRestoration
+ (nullable id<UIStateRestoring>) objectWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder;
@end
複製代碼
UIStateRestoration場景

適用於App進入後臺,後臺停留時間超過系統分配的後臺活躍時間後被系統殺死時的場景。由於當用戶強制退出應用程序時,系統會自動刪除應用程序的保留狀態。在應用程序被終止時刪除保留的狀態信息是一項安全預防措施。若是應用程序在啓動時崩潰,系統也會刪除保留狀態做爲相似的安全預防措施。app

UIStateRestoration調試

根據場景描述,若是要測試應用程序恢復其狀態的能力,則在調試期間不該使用多任務欄來強制終止應用程序。能夠經過設置項目的plist文件下Application does not run in background爲YES。框架

UIApplication對於UIStateRestoration協議的實現接口
#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協議的實現接口
@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協議的實現接口
@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狀態保存和恢復的流程,UIStateRestoration協議類的方法,適用場景,調試策略以及UIApplication、UIViewController、UIView關於1UIStateRestoration1協議所提供的接口方法。 下篇文章咱們將介紹如何實現UI狀態保存和恢復。ide


小編微信:可加並拉入《QiShare技術交流羣》。

關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)

推薦文章:
Swift 運算符
iOS 中精肯定時的經常使用方法
Sign In With Apple(一)
算法小專欄:動態規劃(一)
Dart基礎(一)
Dart基礎(二)
Dart基礎(三)
Dart基礎(四)
iOS 短信驗證碼倒計時按鈕
奇舞週刊

相關文章
相關標籤/搜索