这儿每天共享一个 iOS 的新知识,快来重视我吧

发动类型

在 iOS 上,咱们都清楚发动类型分为“热发动”和“冷发动”。

依照苹果的定义,假如你翻开 App 后滑回到主屏幕并手动杀掉程序,然后当即从头翻开 App,这种发动方式通常称为“热发动”。

假如你刚刚玩了一款需求运用大量内存的游戏,你的 App 或许会被体系杀掉,并清空你的 App 所占用的内存,以允许这个游戏具有更多内存。然后你再次进入你的使用,那么它或许会比你的均匀发动速度慢得多。你的使用程序所依靠的结构和进程也或许需求从头发动和从磁盘分页。这种状况,或者在手机重启后的发动,通常被称为冷发动。

还有一种严格意义上说不叫发动,就是从后台到前台,翻开 App 后,先退到后台,再点击图标翻开,这种状况一般称为“康复”(resume)。

讲讲 iOS 中鲜为人知的

依照 WWDC 的这张图,能够很生动的看出,冷发动像乌龟速度最慢,热发动像兔子,速度次之,康复像豹子,速度最快。

iOS 15 新增的发动类型

在 iOS 15 及更高版本中,体系会学习用户习惯,比方你几点经常翻开某个 App,为了让你发动速度更快,在你翻开之前,体系会先帮你把这个 App 进程发动并参加内存中,这就是苹果新增的一种发动类型,Prewarming Launch(预热发动)

依照苹果的文档,预热会发动 App 进程,直到(但不包含),main() 调用 UIApplicationMain。可是经过我的测验,预热发动不但会调用到 main 函数,甚至有时分会调用到 Appdelegate 中的 application(:, didFinishLaunchingWithOptions:) 办法。因此苹果的文档是不精确的(也或许是个 bug)。

预热发动带来的问题

虽然预热发动能够让发动速度更快,这确实提升了用户体会,但同时也带来了一些问题。

比方市面上许多 APM 东西,例如 FirebaseSentry 等,统计发动时刻都是从进程发动到第一个页面展示出来,假如这次发动是预热发动,那么就或许导致发动时刻呈现非常大的差错,比方进程发动时刻为早上 8 点,或许用户晚上 8 点才发动 App。

另一个问题是预热发动下有些 API 是无法正常调用的,比方钥匙串相关的 API 就无法正常调用,正如前面所说,预热发动下或许会走到 application(:, didFinishLaunchingWithOptions:) 办法,也就是说在这个办法调用的时分,之前所有访问钥匙串的代码或许都是无效的,比方你在 +load() 办法里访问了不能访问的 API,就会导致非预期的成果发生。

解决方案

这时分大家或许会想,假如能够知道这次发动是否为预热发动就好了,可是苹果并未供给相关的 API,可是国外有个 iOS 开发小哥发现苹果在环境变量中增加了一个名为“ActivePrewarm” 的字段来符号是否为预热发动,那么咱们就能够顺畅运用这个符号来知道是否为预热发动了:

if ProcessInfo.processInfo.environment["ActivePrewarm"] == "1" {
    print("本次发动为预热发动")
} else {
    print("本次发动为非预热发动")
}

能够测验经过以下步骤测验预热发动:

  1. 发动你的 App

  2. 简单运用一瞬间

  3. 强制退出 App

  4. 锁定设备,放置大概约 30 分钟

  5. 解锁设备

  6. 再次发动使用程序

以上步骤有概率复现预热发动的状况。

然后就能够根据是否为预热发动来分别解决上边提到的问题,衡量发动时刻的时分能够把预热发动的状况过滤掉。

假如为预热发动,把无法正常调用的 API 放到发动成功之后。

这儿每天共享一个 iOS 的新知识,快来重视我吧

本文同步自微信公众号 “iOS新知”,每天按时共享一个新知识,这儿仅仅同步,想要及时学到就来重视我吧!