ViewController Programming Guide 笔记(三)

Preserving and Restoring State

View controller 可以保留 app 的一些设置,以便于下次启动时恢复上次的设置。保留和恢复状态的过程是自动的,但你要告诉 iOS 你 app 的那部分数据需要保存,通常需要做以下步骤:

  • (必须)分配一个 恢复标识符 给你的 VC
  • (必须)告诉 iOS 在启动时,如何创建或定位一个新的 view controller
  • (可选)为每一个 view controller,存储那些需要返回到原始配置的数据

Tagging View Controllers for Preservation

UIKit 只会保存你告诉他需要保存的 VC,每个 view controller 都有一个 restorationIdentifier 属性,默认值为 nil,只有你为其设置一个有效的字符串,UIKit 才能保存 VC 状态,你可以通过编程方式和 storyboard 的方式来为其分配一个值。

当你分配了一个 restoration identifiers,记住所有的 父 VC 也必须有一个 restoration identifiers,在保存过程中,UIKit 会从 windows 的根 VC 一直到 view controller 的整个继承树,如果其中的一个 VC 并没有 restoration identifier,那么他和他的子 VC 都会被忽略

Choosing Effective Restoration Identifiers

UIKit 稍后会使用你的 restoration identifier 字符串来创建 view controller,restoration identifier 一般要求唯一的。

Excluding Groups of View Controllers

想要某个 VC 极其 子 VC 都不被保留,可以设置 父 VCrestoration identifier 为 nil

在保留状态时,排除一部分 VC,并不会在稍后的恢复过程中移除他们,而是这部分 VC 将会通过 SB 创建,而那些保留了状态的,则通过 restoration 过程创建

从自动保持状态中排除这些 VC 并不妨碍你手动来保存

Preserving a View Controller’s Views

一些 view 的状态信息也需要保持,比如 scrollView 的 scroll position,而这些状态信息与 VC 关系不大。

  • 为 view 的 restorationIdentifier 属性分配有效的字符串
  • 该 view 的 VC 也要有一个合法的 restorationIdentifier
  • 对于 table view 和 collection views 配置一个 data source 部署 UIDataSourceModelAssociation 协议

为 View 分配一个 restoration identifier,告诉 UIKit 将 view 的状态写入 preservation archive,稍后 VC 恢复时,UIKit 也会将 view 恢复到之前的状态。

Restoring View Controllers at Launch Time

在第一次启动时,UIKit 会创建或找出相关的 VC,来组成用户界面,UIKit 会按照如下顺序来找出 VC:

  • 如果 view controller 有一个 restoration 类,UIKit 会请求这个类提供 view controller。 UIKit 会调用 viewControllerWithRestorationIdentifierPath:coder: 来检索恢复相关 view controller
  • 如果 view controller 没有一个 restoration 类,UIKit 会要求 app delegate 来提供这个 view controller。UIKit 会调用 application:viewControllerWithRestorationIdentifierPath:coder: 来查询没有 restoration 类的 view controller。如果返回 nil,则尝试查找隐含的 VC
  • 如果 view controller 存在正确的 restoration 路径,则 UIKit 会使用这个对象。即启动时,UIKit会基于这些路径来找到他们
  • 如果这些 view controller 最初是通过 storyboard 文件加载的,UIKit 使用这些保持的 storyboard 信息来定位和创建,在恢复过程中,UIKit 会找到相关的 storyboard 文件来进行初始化。

将 restoration class 分配给 view controller,会阻止 UIKit 隐式搜索 VC。使用 restoration class 给你在『是否真的想要创建一个视图控制器』上更多的控制权。例如,如果您的类决定 VC 不应该被重新创建,则 viewControllerWithRestorationIdentifierPath:coder: 方法可以返回 nil。当没有 restoration class 可以展示时,UIKit 将尝试找到或创建 view controller 然后恢复他。

当你使用 restoration class 时,viewControllerWithRestorationIdentifierPath:coder: 会创建一个类的新实例,执行最小化的初始化,然后返回所产生的对象。下面的例子中展示了如何使用该方法从 storyboard 中恢复 view controller

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

当手动重新创建 VC 时,重新分配恢复标识符(restoration identifier)和恢复类(restoration class)是一个好的习惯。恢复状态最简单的办法是抓取 identifierComponents 数组中的最后一项并将其分配给您的 view controller。

在启动时对于那些从 main storyboard 文件中创建的对象,不要为每一都创建新的实例,而是让 UIKit 隐式地找出来,或者通过 application:viewControllerWithRestorationIdentifierPath:coder: 方法来找出存在的 objects

Encoding and Decoding Your View Controller’s State

你可以在保留状态阶段通过 encodeRestorableStateWithCoder:decodeRestorableStateWithCoder: 方法来对状态进行加密和解密,这个过程是可选的,但被官方所推荐,你可以保持和恢复如下类型的信息:

  • 正在显示的任意数据信息
  • 对于容器 VC,当前的 child vc 的引用
  • 关于当前选中的信息
  • 对于用户可配置的视图,保持当前的配置信息

在你的加密(encode)和解密(decode)方法中,你可以加密任意对象和数据,这就要你的对象支持 NSCoding 协议。但是 view 和 view controller 除外,因为并不使用 NSCoding 来保持他们的状态,而是 coder 保存这些对象的 restoration identifier ,然后添加到 preservable 对象列表中,这会导致 encodeRestorableStateWithCoder: 方法被调用

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

Coder 对象在加密和解密过程中并不会共享,因此对于每一个对象来说,这个 coder 对其来说都是独一为二,你也不用担心命名空间冲突之类的问题

Tips for Saving and Restoring Your View Controllers

当你的 view controller 支持 preservationrestoration,请遵循以下指导方针:

  • 您可能并不想要保留所有视图控制器
  • 避免在恢复过程中 VC 之间相互交换信息
  • 按照规范使用 view controller,随后系统保存状态时才能如你所愿的工作

-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!