标签栏和导航控制器应用程序中的状态恢复

State Restoration in Tab Bar and Navigation Controller App

目标: 我正在尝试恢复基于选项卡控制器的应用程序的状态(每个选项卡上都有导航控制器)。

问题:重新启动时,所选选项卡似乎已按预期恢复,但该选项卡内的导航层次结构并未恢复。

发展:

  1. 我首先从项目模板开始"Tab based app"。
  2. 接下来,我将恢复 ID 添加到子视图控制器和选项卡栏控制器。
  3. 在应用程序委托中,我实现了 application(_:shouldSaveApplicationState:)application(_:shouldRestoreApplicationState:)

我 运行 然后是应用程序,切换到第二个(右侧)选项卡,点击主页,终止。 o 重新启动,显示右侧选项卡(如预期)。 到目前为止一切顺利。

  1. 接下来,我转到故事板并将两个子视图控制器嵌入到各自的导航控制器中,并为它们分配恢复 ID。

我 运行 应用程序,恢复仍然有效。 还是不错的。

  1. 接下来,我添加一个"detail"视图控制器;它的 class 是故事板 UIViewController 的自定义子 class,具有配置调试标签内容及其视图背景颜色的属性。

  2. 我在每个选项卡的顶部视图控制器上放置了一个 "Show Detail..." 按钮,并从每个选项卡创建一个 segue 到(共享)详细视图控制器。所以现在我的故事板看起来像一个六边形(另外,两个 segues 都有在 Interface Builder 中设置的标识符)。因此,左右顶视图控制器共享相同类型的 "detail" 视图控制器。在展示中,它被配置为区分它被推到的位置(见下一点)。

  3. 在每个顶视图控制器的 prepareForSegue(_:sender:) 方法中,我以不同方式配置推送的详细视图控制器:不同的文本和背景颜色("left" 和蓝色,以及 "right" 和红色)。

  4. 我将代码添加到详细视图控制器以保存和恢复文本和背景颜色属性的状态:encodeRestorableStateWithCoder(_:)decodeRestorableStateWithCoder(_:)。此外,我实现了 viewDidLoad() 以便在视图中反映这些属性的值。每当它被实例化并通过 segue 推送到导航中时,首先设置属性,然后用于配置 viewDidLoad() 中的视图。每当它在恢复期间实例化时,属性都会在 decodeRestorableStateWithCoder(_:) 中设置并类似地在 viewDidLoad().

  5. 中使用

...但是当我 运行 这段代码时,最后选择的选项卡被恢复,但只恢复到顶部视图控制器 -left or right-, 不是细节。有趣的是,最后设置为细节视图控制器的背景颜色瞬间闪烁。

我在encodeRestorableStateWithCoder(_:)decodeRestorableStateWithCoder(_:)中放置了断点,但只有第一个被执行(encode)。

  1. 想知道可能遗漏了什么,我继续实施应用委托的 application(_:viewControllerWithRestorationIdentifierPath:coder:)(始终返回 nil,但记录传递的路径组件)。

关于是否需要这种方法,文档不是很清楚,无论如何,即使没有它,除了细节之外的所有视图控制器似乎都能完美恢复。我添加了代码以根据最后一个路径组件(即该控制器的恢复 ID)实例化每个视图控制器并返回它。

现在,调用了 decodeRestorableStateWithCoder(_:) ,但导航仍会在一瞬间后返回到选项卡的顶部视图控制器。

所以,这是怎么回事?在标签栏 + 导航控制器应用程序中实现状态保存和恢复我缺少什么?

修复: 所以,我的代码有几个问题...

  1. 事实证明,就我而言,我不需要实施application(_:viewControllerWithRestorationIdentifierPath:coder:)。 (见comments of this answer

  2. 我对 encodeRestorableStateWithCoder(_:)decodeRestorableStateWithCoder(_:) 的实现 没有打电话给 super(如上述问题的 accepted answer 中所建议)。

  3. 最后,我得到了正确的视图控制器(细节),但是它的子视图的状态(文本标签内容和主视图背景颜色)处于初始的空状态(未恢复)到它们的最后状态——即文本标签内容和背景颜色)。正如 this question 中提到的,viewDidLoad() 是 而不是 decodeRestorableStateWithCoder(_:) 之后调用(就像我假设的那样),所以我从 viewDidLoad()decodeRestorableStateWithCoder(_:) 更新 UI.

像往常一样,在搜索或尝试对我的代码进行足够的修改之前,我匆匆 post 提出了一个问题(抱歉...)。

我希望这至少对其他人有所帮助。

像往常一样,我会等几天再接受我自己的答案,以防有人提供更多信息。