B5a5fbdf2e071fd5ffdd6a52aeb8eeb8
App多窗口支持架构

前言

本文主要分三个方面进行讨论。首先,我们将概述为了实现多窗口支持,App 生命周期在iOS13中的变化。然后我们将深入探讨新的 UIScene Delegate,以及我们应该在这里构建怎样的代码。最后,我们将介绍 ArchitectureKit 的一些最佳实践,确保为用户提供一致,无感知的多任务处理体验。

App 生命周期的变化

App 生命周期的职责:

iOS 12 及之前:

  • 处理 App 的生命周期

  • UI 的生命周期

iOS 13:

  • 处理 App 生命周期和新的 Scene Session 生命周期

  • UI 的生命周期是由 Scene Delegate 来处理的

在iOS12及之前,App Delegate 有两个主要职责。

第一个是通知 App 进程级别相关事件。 因此,系统会在您的进程启动或即将终止时通知 App Delegate 相关消息。

App Delegate 的第二个职责在于让我们的应用知道其 UI 的状态。 因此,通过某些方法,例如重新载入前台 App 将重新激活,系统将由 App Delegate 通知对应的 UI 状态变化。

这种模式在 iOS 12 及之前完全运行正常,因为应用程序只有一个进程,而且只有一个用户界面实例相匹配。

iOS 12 及之前,我们在构建 App Delegate 代码时,大致如下:

在完成初始化的回调中,这里做了两件事, 首先执行了一次连接到数据库或初始化数据结构的非 UI 全局操作,然后立即进行了用户界面的配置操作。

Why?这是因为 App 现在虽然仍共享同一个进程,但可能有多个用户界面实例或 Scene Session。这就意味着 App Delegate 的职责需要为此做一些变更。

Scene Delegate

在iOS13中,App Delegate 仍然负责进程的事件以及生命周期,但它不再负责与 UI 生命周期相关的任何操作。UI生命周期相关事件都将由新的 UIScene Delegate 进行处理。

对于开发者,有哪些影响?

以前在App Delegate中执行的任何UI操作现在都需要迁移到 Scene Delegate 中的相应方法。

实际上,在iOS 13中,如果我们使用了新的 UIScene 生命周期进行代码构建,UIKit 将不会调用与 UI 状态相关的所有 App Delegate 方法; 所有UI状态相关将通过 Scene Delegate 进行调用,大多数方法都有一对一的映射。

如果我们想在 iOS 13 上采用多窗口支持,并不需要太担心旧版本的适配问题,我们只需同时保留新旧两组代理方法即可,UIKit 将自动在运行时调用正确的方法集。

在我们深入研究具体的 Scene Delegate 相关代理方法之前,还需要介绍一下 App Delegate 的另外一个额外责任:系统会在将要创建及销毁 Scene Session 时通知 App Delegate。

配置新 Session

我们以下面的蓝色 App 为例,来分析具体的生命周期方法调用。

首先,第一次启动,我们来观察调用堆栈。 App Delegate 中依旧调用了 didFinishLaunchingWithOptions 方法。

同时要说明的是,在这里构建一次性非 UI 相关初始化代码是合理的。 在这之后,系统将创建一个 Scene Session。但在创建实际的 UIScene之前,系统会向我们的应用程序确认 UIScene 的相关配置。 这些配置包括要创建 Scene 的 Scene Delegate,Storyboard 以及指定的 Scene 子类。

值得注意的是,我们也可以在代码中动态定义这些 Scene 的配置,或者最好在info.plist中静态定义这些 Scene 配置。

我们可以配置一个主 Scene 配置,同时也可能有一个辅助 Scene。 因此,我们应该确认此处提供的相应 options参数,以将其用作选择正确 Scene 配置的上下文。一旦我们定义了这些配置,例如在 info.plist 中,就非常简单了,只需按对应名称引用,同时确保传入 Session 角色的角色设定。

至此应用已启动,我们创建了一个 Scene Session。 但是目前我们仍然不会看到任何 UI。

但是我们的 Scene Delegate 确实连接到了对应Scene Session,Why?那是因为我们需要在此使用新的UIWindow初始化方式设置我们的UIWindow。

我们传递了相应的 Session。但是,我们还需要检查任何相关的用户活动或状态恢复活动以配置我们的窗口。

完成相关配置后,现在我们可以看到我们的应用程序了。

Scene 断连

那么,当我们的用户上滑返回桌面时会发生什么?

这时,我们熟悉的 didEnterBackground 方法将会在 Scene Delegate 中被调用。 但有趣的是,在之后的某个时间点,我们的 Scene 可能会断开连接。

那这是意味着什么呢?

为了进行资源回收,系统可能会在 Scene 进入后台后的某个时间点从内存中释放该 Scene。 这也意味着我们的 Scene Delegate 将从内存中释放,并且Scene Delegate所持有的任何 Window 及 View 的实例也将被释放。

这让我们有机会销毁和释放内存中与此 Scene 相关的可能被应用中其他逻辑所 retain 的任何大型资源。 但是,要注意我们不应该使用它来删除任何用户数据或永久状态,因为 Scene 可能会重新连接并返回数据。

top Created with Sketch.