4.1 用 SwiftUI 恢复应用状态
5 分钟阅读
原文链接: https://developer.apple.com/documentation/swiftui/restoring-your-app-s-state-with-swiftui
4.1 用 SwiftUI 恢复应用状态
保留用户当前的活动,为使用者提供应用连续性。
概述
这个 SwiftUI 示例项目演示如何保留应用的状态信息,并在后续启动时把应用恢复到之前的状态。在后续启动时把界面恢复到上一次的交互位置,可以为用户提供连续性,让他们快速完成正在进行的任务。
在使用应用时,用户会执行影响用户界面的操作。例如,用户可能正在查看某一页信息;用户离开应用后,操作系统可能为了释放它占用的资源而终止该应用。用户可以回到离开时的位置——而界面状态恢复正是让这种体验变得无缝的核心部分。
这个示例应用演示了在系统中断应用的情况下如何使用状态保留与恢复。示例项目管理一组产品,每个产品都有标题、图片以及其他可以查看和编辑的元数据。该项目展示了如何在 DetailView 中保留和恢复某个产品。
配置示例代码项目
在 Xcode 中,于 iOS 目标的 Signing and Capabilities 标签页里选择你的开发团队。
启用状态保留与恢复
这个示例代码项目使用 SwiftUI 的 Scene 来管理应用的用户界面,其生命周期由系统管理。在 iOS 上,状态恢复在窗口或场景层级尤其重要,因为窗口会频繁地出现和消失。必须为每一个窗口或场景保存并恢复相关状态。在 iPad 上这一点尤其重要,因为应用切换器中的应用不一定正在运行。场景层级的状态恢复会维持「它们仍在运行」的错觉。
为支持状态保留与恢复,这个示例使用 NSUserActivity 对象。对每一个用户活动,应用都必须在其 Info.plist 中提供一个已定义的活动类型。
使用场景存储
SwiftUI 有「存储场景数据」的概念,即 SceneStorage。它的工作方式与 State 类似,是一种由键值对构成的属性包装器类型。键让系统能够正确地保存和恢复该值。值必须是 plist 类型,这样系统才能正确地保存和恢复它。iOS 会用这个键值接收场景存储,然后对持久化的、按场景存储的数据进行读写。操作系统代替用户管理场景存储的保存与恢复。支撑场景存储的底层数据并不直接可用,因此应用必须通过 @SceneStorage 属性包装器访问它。操作系统不保证数据何时被持久化、以及多久持久化一次。场景存储中的数据不一定等同于应用的数据模型。场景存储的用意是与数据模型配合使用。归根结底,请把场景存储看作「限定在某个场景内的状态」。不要用场景存储保存敏感数据。
每个需要自己保存状态的视图都实现一个 @SceneStorage 属性包装器。例如,ContentView 用一个来恢复所选的产品:
| |
DetailView 用一个来恢复它当前选中的标签页:
| |
注意:每个场景存储键都必须唯一,并恰当地限定在应用中它所作用的区域或用途上。由于场景存储只作用于本应用,不必给它加上应用的 bundle 标识符前缀。必要时可以使用一些消歧前缀,以确保其唯一性。
用活动对象恢复应用状态
NSUserActivity 对象捕获应用在当前时刻的状态。例如,其中可以包含应用当前正在显示的数据信息。系统会保存这个对象,并在应用下次启动时把它交还给应用。示例在用户关闭应用或应用进入后台时创建一个新的 NSUserActivity 对象。
每个想要为接力(Handoff)、Spotlight 等公开 NSUserActivity 的 SwiftUI 视图,都必须指定 userActivity(:isActive::) 视图修饰符来公开该 NSUserActivity。activityType 参数是用户活动的类型,isActive 参数表示是否公开指定类型的用户活动(该参数默认为 true),以及是否使用指定的处理程序来填充用户活动的内容。用户活动的作用范围仅限于该视图所在的场景或窗口。多个视图可以公开同一个活动类型,它们的处理程序都可以为用户活动的内容做出贡献。注意,只有 isActive 参数为 true 的 userActivity 视图修饰符,其处理程序才会被调用。如果没有任何 userActivity 视图修饰符把 isActive 指定为 true,iOS 就不会公开该用户活动。
每个想要处理传入 NSUserActivities 的 SwiftUI 视图,都必须指定 onContinueUserActivity(_:perform:) 视图修饰符。它接收 NSUserActivity 类型,以及一个当该视图在其所在场景或窗口中收到指定活动类型时要调用的处理程序。
| |
测试状态恢复
这个示例会恢复下列用户界面:
- 详情视图控制器——在集合视图中轻点某个产品以打开它的详情信息。应用会恢复所选的产品和选中的标签页。
- 详情视图控制器的编辑状态——在详情视图中轻点 Edit。应用会恢复编辑视图及其内容。
- 次级窗口——(仅限 iPad)从集合视图中把某个产品拖到设备屏幕的左侧或右侧,创建第二个场景窗口。应用会恢复该场景及其产品。
状态恢复可以在设备和模拟器上测试。调试这个示例项目时,当用户强制退出应用,系统会自动删除它所保留的状态。删除保留的状态信息是一项安全预防措施。此外,如果该应用在启动时崩溃,系统也会删除保留的状态。
要测试示例应用恢复自身状态的能力,调试时不要用应用切换器强制退出它。请改用 Xcode 停止应用,或者以编程方式停止应用。另一种做法是:按 Home 键让示例应用挂起,然后在 Xcode 中停止调试器。再用 Xcode 启动示例应用,SwiftUI 就会启动状态恢复流程。
要配合接力(Handoff)使用 Spotlight,请按以下步骤操作:
- 在 Xcode 中,于
DetailView.swift的onContinueUserActivity闭包处设置断点。 - 运行示例项目。
- 在集合视图中轻点某个产品(“Cherries”),导航到它的详情信息。
- 从屏幕顶部下拉系统面板(以促使 Spotlight 更新索引并请求该活动)。注意,iOS 会调用
DetailView的userActivity闭包。 - 回到应用,再回到集合视图。
- 轻点一个不是 Cherries 的产品(例如 Mango)。
- 按 Home 键让应用挂起。
- 在主屏幕上向下轻扫,打开 Spotlight 窗口。
- 在 Spotlight 搜索框中输入 “Cherries”。搜索结果会显示 “Show Cherries Product”。
- 轻点它。注意,
DetailView的onContinueUserActivity闭包会被调用,DetailView会显示 Cherries 产品。