前言:iOS 开发中,我们都知道一个App点击了home按键或者切换至其他应用时,将进入后台。随着时间的推移,App会经历后台运行,后台悬挂,最后被杀死。假如有这样一个场景:
场景1:用户正在使用我们App进行个人信息的编辑,突然接到了一个电话,使得App进入后台并且通话时间超过了App后台保活的时间。当用户通话完毕的时候,返回继续填写,却发现App重新启动了,并且用户之前填写的数据,都没有保存,需要重新输入?用户的体验会很不好。
对于此问题,我们可能会说让App后台保持活跃不就行啦。是的,这是个很好的解决方案。但是除了这个方案,我们是不是有其他的办法实现UI界面和数据的保存和恢复。答案是肯定的,接下来我们会介绍一种方案UIStateRestoration
。
一、关于UIStateRestoration
UIStateRestoration出现于iOS 6.0以后的API中。主要帮助我们实现特定场景下的UI保存和恢复。UIStateRestoration是一个协议类,在苹果的系统中UIKit框架下的UIApplication、UIViewController、UIView都实现了UIStateRestoration协议。
关于UI状态从应用程序启动到恢复以及UI状态保存时相关API的调用顺序,用官网的图解大家可以理解的更清楚。
UI状态恢复,只有当AppDelegate实现application:shouldRestoreApplicationState:
并且在方法中返回true时才会生效。 UI状态保存,只有当AppDelegate实现application: shouldSaveApplicationState:
并且在方法中返回true时才会生效。
二、UIStateRestoration的介绍
系统进行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);复制代码
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*)identifierComponents coder:(NSCoder *)coder; @end复制代码
UIDataSourceModelAssociation协议:目前只有UITableView and UICollectionView实现了这个协议。
官网说明: UIDataSourceModelAssociation.
@protocol UIDataSourceModelAssociation - (nullable NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view; - (nullable NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view; @end复制代码
UIStateRestoring协议:实现UIStateRestoring协议,可以让我们自定义的视图(非UIView和UIViewController子类)加入状态恢复。前提必须使用UIApplication的
+ (void)registerObjectForStateRestoration:(id
方法注册。)object restorationIdentifier:(NSString *)restorationIdentifier
+ (void)registerObjectForStateRestoration:(id)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@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`或视图控制器,否则将被忽略。 个人理解:类似继承体系模式,方便归整清楚恢复的路径,帮助我们进行一定顺序和层次的恢复。*/ @property (nonatomic, readonly, nullable) idrestorationParent; // 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) ClassobjectRestorationClass; // 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`的`objectRestorationClass `,则该类必须实现此协议。 @protocol UIObjectRestoration + (nullable id) objectWithRestorationIdentifierPath:(NSArray*)identifierComponents coder:(NSCoder *)coder; @end复制代码
UIStateRestoration场景
适用于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*)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)@property (nullable, nonatomic, copy) NSString *restorationIdentifier NS_AVAILABLE_IOS(6_0); @property (nullable, nonatomic, readwrite, assign) ClassrestorationClass 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状态保存和恢复。
小编微信:可加并拉入《QiShare技术交流群》。
关注我们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)
推荐文章:
Swift 运算符
iOS 中精确定时的常用方法
Sign In With Apple(一)
算法小专栏:动态规划(一)
Dart基础(一)
Dart基础(二)
Dart基础(三)
Dart基础(四)
iOS 短信验证码倒计时按钮
奇舞周刊