[译] 状态恢复入门教程

在这篇状态恢复教程中,咱们将了解如何使用 Apple 的状态恢复接口来提高用户的应用体验。前端

注意:Xcode 7.三、iOS 9.3 和 Swift 2.2 已于 2016-04-03 更新。android

在 iOS 系统中,状态恢复机制是一个常常被忽略的特性,当用户再次打开 app 的时候,它可以精确的恢复到退出以前的状态 - 而不用关心发生了什么。ios

某些时候,操做系统可能须要从内存中删除你的应用;这可能会严重中断用户的工做流。你的用户不再必担忧由于切换到另外一个应用而影响到工做的事情了。这就是状态恢复机制所起到的做用。git

在这篇恢复教程中,你将更新现有应用以添加保留和恢复功能,并在其工做流可能被中断的状况下提高用户体验。github

入门

下载本教程的 入门项目。该应用名为「Pet Finder」;对于那些碰巧在寻找毛茸茸猫科动物陪伴的人来讲,这是一款方便的应用。swift

运行该应用;你将会看到一张关于猫的图片,这表明你有机会能够领养它:后端

Pet Finder

向右滑动便可与新的毛茸茸的朋友配对;向左滑动表示你想要继续传递这个绒毛球小猫。你能够从匹配选项卡栏中查看当前全部的匹配列表:app

Matches

点击来查看所选中朋友的更多详细信息:框架

Details

你甚至能够编辑你新朋友的名字(或年龄,若是你是在扭曲事实):dom

Edit

你但愿当你离开该应用而后返回时,你会被带回到上一次查看的同一个毛茸茸朋友。但真的是这样吗?要知道答案的惟一方法就是测试它。

状态恢复测试

运行应用,向右滑动至少一只猫,查看你的匹配项,而后选择一只猫并查看他或她的详细信息。按组合键 Cmd + Shift + H 返回主页面。若是存在任何逻辑上的状态,它都会被保存而且都将在此时运行。

接下来,经过 Xcode 中止应用:

Stop App

当用户手动杀死应用或状态恢复失败时,状态恢复框架将丢弃任何状态信息。之因此存在这些检查,以免你的应用不会陷入无线循环的错误状态以及恢复崩溃。谢谢,Apple!:]

注意:你没法经过应用切换器自行终止应用,不然状态恢复将没法正常工做。

再次启动应用;你将回到主屏幕,而不是宠物详情视图。看起来你须要本身添加一些状态恢复逻辑。

实现状态恢复

设置状态恢复的第一步是在你的应用代理中启用它,打开 AppDelegate.swift 并添加如下代码:

func application(application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
  return true
}

func application(application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
  return true
}
复制代码

应用代理中有五个方法来管理状态恢复。返回 trueapplication(_:shouldSaveApplicationState:),告诉系统保存 view 的状态,并在应用处于后台运行状态时查看 view controller。返回 trueapplication(_:shouldRestoreApplicationState:),告诉系统在应用从新启动时尝试恢复原始状态。

你能够在某些状况下让这些代理方法返回 false,例如在测试时或用户运行的应用的旧版本没法恢复时。

构建并运行你的应用,而后导航到猫的详情页。按住组合键 Cmd + Shift + H 让你的应用进入后台,而后经过 Xcode 中止应用。你将看到如下内容:

Pet Finder

confused

与你以前看到的彻底相同!只选择进行状态恢复还不够。虽然你已在应用中启用了保存和恢复,但 view controller 还没有参与。要解决这个问题,你须要为每一个场景提供一个恢复标识符

设置恢复标识符

恢复标识符只是一个 view 和 view controller 的字符串属性,UIKit 使用它来将这些对象恢复到以前的状态。它存在一个 UIKit 与你但愿保留的对象通信的值。只要这些属性的值是惟一的,它们的实际内容并不重要。

打开 Main.storyboard,你将看到一个 tab bar controller、一个 navigation controller 和三个自定义 view controller:

cinder_storyboard

恢复标识符能够在代码中或在 Interface Builder 中设置。简单起见,在本教程中你将在 Interface Builder 中进行设置。你能够进入并为每个 view controller 设置一个惟一的名称,但 Interface Builder 有一个 Use Storyboard ID 的快捷选项,它容许你将 Storyboard ID 用于恢复标识符。

Main.storyboard 中,单击 tab bar controller 并打开 Identity Inspector。启用 Use Storyboard ID 选项,以下所示:

Use Storyboard ID

这样会把 view controller 行存档记录,而且在状态恢复过程当中进行还原。

对 navigation controller 和其它三个 view controller 重复此过程。确保你已经为每一个 view controller 选中了 Use Storyboard ID。不然你的应用可能没法正常恢复其状态。

请注意,全部 controller 都已经具备 Storyboard ID,而且该复选框仅使用已做为 Storyboard ID 的相同字符串。若是你未使用 Storyboard ID,你须要手动输入一个惟一的 Storyboard ID

恢复标识符聚集在一块儿,经过应用中任何 view controller 的惟一路径造成恢复路径;它与 API 中的 URI 相似,其中惟一路径标识每一个资源的惟一路径。

好比,如下路径表明 MatchedPetsCollectionViewController

RootTabBarController/NavigationController/MatchedPetsCollectionViewController

经过这些设置,应用将记住你中止使用时的 view controller(大多数状况下),而且任何 UIKit view 都将保留其先前的状态。

构建并运行你的应用;返回宠物详情页测试恢复流程。暂停和恢复应用后,你应该看到如下内容:

No Data

虽然系统恢复了正确的 view controller,但它彷佛缺乏填充 view 所需的猫对象。如何恢复 view controller 及其所需的对象呢?

UIStateRestoring 协议

在实现状态恢复方面,UIKit 为你作了不少工做,可是你的应用须要负责自行处理一些事情:

  1. 告诉 UIKit 它想参与状态恢复,就是你在应用代理中所作的那些。
  2. 告诉 UIKit 应该保留和恢复哪些 view controller 和 view。你经过为 view controller 分配恢复标识符来解决此问题。
  3. 编码和解码任何须要重建 view controller 以前状态的相关数据。你尚未这样作,但这是 UIStateRestoring 协议须要解决的问题。

每一个具备恢复标识符的 view controller 都将在保存应用时接收 UIStateRestoring 协议对 encodeRestorableStateWithCoder(_:) 的调用。另外,view controller 将在应用恢复时接收 decodeRestorableStateWithCoder(_:) 的调用。

要完成恢复流程,你须要添加对 view controller 进行编码和解码的逻辑。虽然该过程多是最耗时的,但概念相对简单。你一般会编写一个扩展来增长协议的一致性,可是 UIKit 会自动关注册 view controller 以符合 UIStateRestoring - 你只须要覆盖适当的方法。

打开 PetDetailsViewController.swift,并在类的末尾添加如下代码:

override func encodeRestorableStateWithCoder(coder: NSCoder) {
  //1
  if let petId = petId {
    coder.encodeInteger(petId, forKey: "petId")
  }

  //2
  super.encodeRestorableStateWithCoder(coder)
}
复制代码

如下是上述代码要作的事:

  1. 若是当前猫对象存在 ID,使用提供的编码器进行保存以便稍后检索。
  2. 确保调用 super 以便继承的状态恢复功能的其它部分可以按照预期发生。

经过少许的修改,如今你的应用能够保存当前猫的信息。但请注意,你实际上并未保存猫的模型对象,而是稍后可用于获取猫对象的 ID,当你保存经过 MatchedPetsCollectionViewController 选择的猫时,可使用相同的概念。

Apple 很是清楚,状态恢复用于存档建立 view 层次结构所需并将应用恢复到其原始状态的信息。每当应用进入后台时,使用提供的编码器来保存和恢复简单模型数据是很诱人的,可是只要状态恢复失败或用户杀死应用,iOS 将会丢弃全部存档数据。因为你的用户每次从新启动应用时都不会很是乐意回到起始页,因此最好遵循 Apple 的建议并仅使用此策略保存状态恢复。

如今你已经在 PetDetailsViewController.swift 中实现了编码,你能够在下面添加相应的解码方法:

override func decodeRestorableStateWithCoder(coder: NSCoder) {
  petId = coder.decodeIntegerForKey("petId")

  super.decodeRestorableStateWithCoder(coder)
}
复制代码

解密 ID 并将其设置回 view controller 的 petId 属性。

一旦解码了 view controller 的对象,该 UIStateRestoring 协议就会提供 applicationFinishedRestoringState() 的其余配置步骤。

PetDetailsViewController.swift 中添加如下代码:

override func applicationFinishedRestoringState() {
  guard let petId = petId else { return }
  currentPet = MatchedPetsManager.sharedManager.petForId(petId)
}
复制代码

上面是基于解码后的宠物 ID 设置当前宠物,并完成 view controller 的恢复。固然,你能够在 decodeRestorableStateWithCoder(_:) 执行此操做,但最好保持逻辑分离,由于当它们所有捆绑在一块儿时它将变得笨拙。

构建并运行你的应用;导航到宠物的详情页并让应用置于后台,而后经过 Xcode 杀死该应用以触发保存序列。重启应用并验证你的毛茸茸玩具是否按预期显示:

Details

你已经学习了如何恢复经过 storyboard 建立的 view controller。但你在代码中建立的 view controller 应该如何处理呢?要在运行时恢复基于 storyboard 建立的 view controller,UIKit 要作的是在 main storyboard 中找到它们。幸运的是,恢复基于代码建立的 view controller 几乎同样容易。

恢复基于代码建立的 view controller

视图控制器 PetEditViewController 彻底由代码建立;它用于编辑猫的名字和年龄。你将使用它来学习如何恢复基于代码建立的 view controller。

构建并运行你的应用;导航到猫的详情页,而后点击编辑。修改猫的名字,但不保存你的更改,以下所示:

Edit

如今将应用置于后台并经过 Xcode 杀死它以触发保存序列。重启应用,iOS 将返回宠详情页而不是编辑页:

Details

正如你在 Interface Builder 中构建的 view controller 所作的那样,你须要为 view controller 提供恢复 ID,并添加 UIStateRestoring 协议中的编码和解码方法以便正确恢复状态。

查看 PetEditViewController.swift;你会注意到编码和解码的方法已经存在。逻辑相似于你在上一节中实现的编码和解码方法,但它还具备一些额外的属性。

手动分配恢复标识符是一个简单的过程。在 viewDidLoad() 中调用 super 后当即添加如下内容:

restorationIdentifier = "PetEditViewController"
复制代码

这会为 restorationIdentifier 视图控制器分配惟一 ID。

在状态恢复过程当中,UIKit 须要知道从何处得到 view controller 引用。在你设置 restorationIdentifier 的下面添加如下代码:

restorationClass = PetEditViewController.self
复制代码

这将设置 PetEditViewController 为负责实例化 view controller 的恢复类。恢复类必须采用 UIViewControllerRestoration 协议并实现所需的恢复方法。为此,将如下扩展代码添加到 PetEditViewController.swift 的末尾:

extension PetEditViewController: UIViewControllerRestoration {
  static func viewControllerWithRestorationIdentifierPath(identifierComponents: [AnyObject], coder: NSCoder) -> UIViewController? {
    let vc = PetEditViewController()
    return vc
  }
}
复制代码

这实现了返回类实例所需的 UIViewControllerRestoration 协议方法。如今 UIKit 有了它正在寻找的对象的副本,iOS 能够调用编码和解码方法并恢复状态。

构建并运行你的应用;导航到猫的编辑页。像以前同样更改猫的名字,但不保存更改,而后将应用置于后台并经过 Xcode 将其删除。重启你的应用,并验证你所作的全部工做,为你的毛茸茸朋友提出一个伟大的独特名称并不是都是徒劳的!

Edit

接下来去哪儿?

你能够 在此处如今已完成的项目。状态恢复框架是任何 iOS 开发人员工具包中很是有用的工具;你如今能够将基本恢复代码添加到任何应用,并以此提升你的用户体验。

有关使用该框架可能实现的更多信息,请查看 2012 年2013 年的 WWDC 视频。2013年的演示文稿特别有用,由于它涵盖了 iOS 7 中引入的恢复概念,好比用于保存和恢复任意对象的 UIObjectRestoration 和在需求更复杂的应用中恢复表和集合视图的 UIDataSourceModelAssociation

若是你对本教程有任何疑问或建议,请加入如下论坛讨论!

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索