大多数浏览器和
Developer App 均支持流媒体播放。
-
优化 App 启动
App 启动缓慢会让用户感到失望。了解新的 app 启动 instrument,并探索如何让您的 app 快速启动。深入了解 app 启动期间发生的情况,以及如何尽量减少这个重要时间段的工作、如何排定工作优先级和对其进行优化。听听工程师们在让 iOS app 快速启动方面的技巧和窍门。
资源
-
下载
大家好 我是 Spencer Lewson 我是 Apple 公司 Performance Team 的一名工程师 今天我很高兴告诉你们 如何优化你们 App 的启动 我们今天将讨论 这四个主要议题 首先 什么是启动 不同类型的启动有哪些 以及我们如何 将它们分解为不同的子阶段
接下来 我们将讨论 如何正确估测你们 App 的启动
生活中 iOS 设备 可能处于各种不同的 状态和情况 并且这些 状态和条件可能 产生不一致的启动结果 因此 了解这些状态 以及如何在进行测量时 减少其影响非常重要 在这时候 你们可以查看如何使用 Instruments 来分析和了解 你们的 App 以找到 改进它的机会
最后 我们将为你们提供 有关如何监控 App 启动的 一些可持续且适用于实战的 提示和技巧 以确保你们始终为 所有用户提供愉快的体验 那么 我正在谈论的 App 启动是什么 其实 App 启动是用户体验的中断
这是什么意思呢 让我们来看看
好的 准备 开始
哇 在这台 iPhone 6S Plus 上 启动时间差不多 2.5 秒 这并不像我们用户期望的 那样令人愉快
你们知道 令人愉悦的启动 是非常重要的 因为它经常发生 事实上 在所有 iOS 设备中 它每天都会发生数十亿次
所以 我们做了一些 简单计算 发现 如果每次启动时我们 节省一毫秒 我们将节省共惊人的 162 天启动时间
是的 换句话说
谢谢你们 换句话说 这就是将火箭 发送到火星所需的时间 但由于其他一些原因 这同样很重要 首先 你们 App 的启动是 你们用户对你们 App 的第一印象 因此它应该是愉悦的
现在重要的是要记住 作为开发者 我们倾向于被更新的设备吸引 因此 重要的是要确保 你们在眼前 看到的体验与 你们的用户 在不同 iOS 设备 和不同条件下拥有的 用户体验相同
此外 启动涵盖了 你们代码库的很大一部分 从底层加工到初始化 再到视图创建等等 因此 如果你们发现 你们的启动并不像 用户期望的那样愉悦 那么这也可能表明 你们的代码库的 其他部分也并不那么令人愉悦 最后 启动是一个对于手机是 非常紧张的时间 会涉及大量 CPU 工作和 大量内存工作 因此 你们应该尝试减缓它 因为它会影响系统性能 当然还有你们用户的电池寿命 那么 让我们来看看 我之前谈过的那些启动 有冷启动 暖启动 继续运行通常被称为启动 但其实它不是一个启动
重启后或你们的 App 很长时间未启动时 会发生冷启动
为了启动 App 我们需要将它从磁盘带入内存 启动支持你们 App 的系统端服务 然后生成你们的进程
正如你们所预料的那样 这可能需要一点时间 但幸运的是 一旦发生一次 你们都将体验到暖启动 在这种情况下 你们的 App 仍然 需要被唤醒 但我们已经将你们的 App 带入内存并启动了 那些系统端服务 所以 这会更快一点 也会更一致
最后 还要说说继续运行
当用户从主屏幕 或 App 切换器重新进入你们的 App 时 会发生这种情况
如你们所知 该 App 在此时已经启动 因此速度非常快
你们需要记住的是 在进行估量时 不要将继续运行与启动混淆 所以 鉴于这些信息 如果启动与继续运行一样快速 和令人愉悦 那不是很棒吗 我们怎样才能做到这一点
好吧 我们需要达到 在 400 毫秒内渲染 第一帧的目标
这样我们就可以在 启动动画期间 向用户显示像素 并且在启动动画完成时 你们的 App 就具有 交互性和响应性 这样做的第一步是 了解启动期间发生的情况 那么 让我们启动《地图》
如你们所知 启动通常发生在用户点按 主屏幕上你们的图标时 然后在接下来的 100 毫秒左右内 iOS 将执行必要的 系统端工作以 初始化你们的 App 这给了你们开发者有 大约 300 毫秒来创建视图加载内容 并生成第一帧
现在这个帧不一定 需要完全完成 它可以有一些占位符 用于异步加载数据 但此时你们的 App 应该是 可交互 且有响应的
因此 在这个 Maps 的例子中 所有视窗尚未加载 你们仍然可以启动搜索 并浏览收藏夹 然后在接下来的几百毫秒内 你们可以显示异步加载的 数据并为你们的用户 生成最终帧 让我们仔细看看这些阶段
这六个阶段涵盖所有内容 从系统初始化到 App 初始化 再到视图创建和布局 如果你们的 App 有需要的 还可能有一个扩展阶段 用于数据的异步加载
系统界面的前半部分是 DYLD3 对于你们中那些不熟悉的人 动态链接器会加载 你们的共享库和框架
在 2017 年 我们引入了 DYLD3 它为系统增加了 令人兴奋的优化
好吧 我们很高兴地宣布 在 iOS 13 中 我们会为 你们的 App 带来这些优化
这意味着我们现在会为热启动 缓存运行时依赖项 这应该会给它们带来显著的速度提升 谢谢你们
现在有了一个新的链接器 我们提出了一些新的建议
为了充分利用这些新的改进 我们建议你们 避免链接未使用的框架 因为这可能会产生潜在成本 我们稍后会向你们展示
我们还建议你们 避免动态库加载 例如 dlopen() 或 NSBundle 中的 load() 因为这会损失你们 在缓存中建立的那些优势
最后 这意味着 你们应该硬链接 所有依赖项 因为它现在甚至比以前更快
系统接口的后半部分 是 libSystem Init
这是我们在 App 中 初始化底层系统组件的时候
现在这主要是系统方面的工作 有固定成本 因此 开发者不需要关注该部分
接下来是静态运行时初始化
这在系统初始化 Objective-C 和 Swift 运行次数时会出现
一般来说 你们的 App 不应该在这里做任何工作 除非你有可能存在于代码中的 静态初始化方法 或者更可能是你链接的 框架带来的“惊喜” 通常 我们不建议静态初始化 所以 让我们花点时间谈谈 如何减少其影响
如果你们拥有一个 使用静态初始化的框架 你们要考虑暴露 API 以 尽早初始化你们的栈 但是如果必须使用静态初始化 请考虑将代码移出 + 它在 App 启动期间 总会被调用 就在你在类中第一次使用方法的时候 被懒调用 接下来是 UIKit 初始化
这就是系统实例化 你们的 UIApplication 和 UIApplicationDelegate 的时候 在大多数情况下 这是系统方面的工作 设置事件处理 和与系统的集成
但是你们其实仍然 可以影响此阶段 如果你们在子类 UIApplication 或者在 UIApplicationDelegate 初始化程序中做任何工作 现在我们看看 App 初始化 最重要的东西都在这里 这是作为开发者 可能在你们 App 启动时 初始化程序中做任何工作地方 对于你们之中尚未采用 UIScene API 或针对 iOS 12
或更早版本的用户的人来说 App 初始化 仍然可以用这些 代理回调方法 application:willFinishLaunchingwithOptions 和 application:didFinishLaunchingwithOptions 当你们的 App 显示给用户时 applicationDidBecomeActive 这个方法 会被进一步调用
现在重要的是要知道 如果你没有采用 UIScene API 你应该创建视图控制器 和 didFinishLaunchingwithOptions
这是因为使用 UIScene 时 App 初始化的工作方式略有不同 现在你仍然可以获得 willFinishLaunching 和 didFinishLaunchingwithOptions 但是当你们的 App 显示给用户时 你们将获得 UISceneDelegate 生命周期回调
当然就是带有选项的 scene:willConnectToSession sceneWillEnterForeground 和 sceneDidBecomeActive 你们应该创建视图控制器 和带有选项的 scene:willConnectToSession
重要的是要注意 你们应该只创建 视图控制器和带有选项的 scene:willConnectToSession 以及带有选项的 didFinishLaunching 这是常见的陷阱 当然会导致性能损失 并且可能导致你们代码库中
出现不可预测的错误 无论你们是否 采用了新的 UIScene API 我们对此阶段的建议 通常都是相同的 你们应该推迟 任何不相关的工作 但是没有必要 提交你的第一帧 可以通过将其推送到后台队列 或者稍后再完全执行
如果你们确实采用了 UIScenes 那么你们可以再做一件事 那就是确保你们在场景之间共享资源 当然 这是为了减少 多次不必要地 进行一些工作的开销 要了解有关 UIScenes 的更多信息 那就是确保你们在场景之间这两个会议
接下来是第一帧 渲染阶段 这是相对简单的 这是我们创建视图 执行布局 然后绘制它们的时候
然后我们获取该信息 并将你们的第一帧渲染 用漂亮的像素呈现出来
你们可以通过减少 层次结构中的视图数 来影响此阶段 你们也可以通过 展平视图以减少使用 或延迟加载在启动期间 未显示的视图来实现 你们还应该查看自动布局 看看是否可以减少 正在使用的约束数量
最后 我们有一个扩展阶段 这是从你们第一次 提交到向用户显示 最终帧的 App 特定时间段
这是当你加载 我们谈到的异步数据时 其实不是每个 App 都有这个阶段
但如果你们确实有这个阶段
那么你们的 App 应该具有互动性和响应性 如果你们确实有这个阶段 我们只会就你应该如何处理 这个问题提供广泛性建议 那就是了解正在发生什么 并且你们可以通过 利用 os_signpost API 来标记和衡量 在这两个时期发生的工作
既然我们讨论了启动是什么 让我们谈谈如何获得可用的测量
在任何给定时间 iOS 设备都处于各种 不同的状态和情况下 这可能会在启动时 引入很大的差异 因此 当我们分析和 比较我们的启动结果时 确保我们进行“Apple-Apple”的 对比比较至关重要 因为如果在进行任何更改之前 你的启动结果完全不可预测 你们如何知道 自己是否取得了进展呢 使其可预测的第一步是 消除这些差异来源 例如网络干扰和 后台进程中的干扰
现在我们意识到 这听起来有悖常理 因为这可能会导致 启动不能完全 代表常规使用 但我们想让 你们知道这没关系
拥有一致的结果可以 使评估很好地进展 这一点尤为重要 在 Apple 我们一直在使用这种技术 在开发过程中成功检测回归 并缩短启动时间 然后 我们通过使用 在实际情况中收集的遥测数据 来验证这些性能改进 幸运的是 我们提供了一些关于建立干净 和一致的环境的技巧
首先 重启你们的设备 这将清除任何 不必要的状态 然后让它在接下来的几分钟内 安定下来以清除 任何启动时间工作
你们还可以通过打开飞行模式 或在代码中标记 网络依赖性来 减少对网络的依赖
网络可以引入相当多的差异 接下来是 iCloud
iCloud 是一个很棒的功能 它可以在后台运行 为我们的用户提供无缝体验 但是在后台工作 会干扰 App 的启动 因此 在你们的测量过程中 使用不变的 iCloud 帐户和不变的数据 或完全注销 iCloud 接下来一定要在进行测量时 使用 App 的发布构建版本 当然 这是为了减少测量期间 不必要的调试代码的开销 并利用编译时优化
最后 你们应该使用 热启动进行测量 如前所述 它们更加一致 因为你们的某些 App 可能已经在内存中 并且其中一些 系统端服务可能已在运行 现在我们可以设置 一些数据来测试
创建一致的模拟 数据集非常重要 你们可能需要 为不同类型的用户 提供一些数据集 例如具有少量数据的用户 和具有大量数据的用户 但在理想情况下 你们的 App 应该能够扩展到 任何数量的数据
这就是为什么 在显示第一帧时 只加载必要数据的原因
现在我们准备挑选一些设备了
你们应该选择 对用户重要的各种设备 然后坚持使用它们 强制一致性
请确保将最旧的 设备包含在 最早支持的版本中 这是因为旧设备 和较新设备之间 的性能特征 看起来不同 后者具有不同数量的 RAM 和 CPU 内核
这将确保你们的 所有设备上的 所有用户都能感到愉快
现在我们准备 进行一些测量
我们可以利用新的 XCTest 来在 Xcode 11 中 测试 App 性能
只需几行代码 Xcode 就会重复启动你们的 App 然后提供有关其 执行情况的统计结果
我们稍后会谈到这个
所以 现在我们已经讨论了 启动是什么以及如何衡量它 让我们谈谈如何改进它
当你们在代码和工具中 查看 App 的启动时 你们应该记住 这三个提示和技巧
首先是最小化你们的工作 然后优先考虑你们的工作 最后 优化你们的工作
在最小化工作时 你们应该推迟与 生成第一帧无关的任何内容 这意味着推迟 未显示的视图或尚未使用的 预加热功能等内容
你们还应该避免阻塞主线程 比如网络 I/O 文件 I/O 或其他 因为这会影响启动 将其移动到后台线程 最后 你们应该注意 减少内存使用量分配和操作 内存可能需要时间 接下来 优先工作
这时你们应确保以 正确的服务质量安排工作
现在 在 iOS 13 中 我们对排程器进行了 一些令人兴奋的优化 使你们的 App 启动速度更快 但这意味着 保持优先问题跨线程传播工作 比以往任何时候都更加重要 你们应该看看 2017 年 WWDC 的 《Modernizing Grand Central Dispatch Usage》 它深入探讨了 如何正确处理并发问题
最后 我们要进行优化工作
这应该是在最小化 并考虑优先级之后 剩下的所有东西了 也就是说它应该是 简化的和有限的 例如 限制仅在 启动期间获取所需 数据的数据量 或者懒计算 所需的任何变量和结果
当你们这样做时 请查看你们的方法和算法 看看你们是否可以优化它们 因为你们可以通过 不同的计算结果或 使用不同的数据结构 来获得显着的改进 最后 你们应该缓存你们的资源和复杂功能 当然 这是通过多次 不必要地工作 来减少 CPU 和内存开销 现在 我想把舞台交给 Dan Dan 将为你们提供一个 关于如何在 Xcode Instruments 中使用 新的 App 启动模板 来理解和改进我们的 App 发布的精彩演示 谢谢 Spencer 嗨 大家好 我是 Dan Sawada 我也是 Apple 的 性能工程师之一 今天 我将介绍一个了解 你们的 App 启动的 典型工作流程 并寻找最小化 优先处理 以及优化工作的机会 以便你们可以真正提供 令人愉悦的第一次用户体验
那么 我们开始吧 我今天要展示的 App 叫做《Star Searcher》 这是我们为此次分享会 专门编写的示例 App 如你们所见 这是一个非常典型的 UITableView 列出了我所有想象中的星星 如果单击单元格或星形 除了图片之外 它还会显示一些 描述性模糊状
但是 我们有一个问题
先让我们继续并启动它
准备 开始
所以 这需要花费惊人的 2.5 秒才能启动 不知道我是否可以称之为 令人愉快的 所以 让我们使用 Xcode 和 Instruments 来看看 我们能做些什么
所以 这里我们有 《Star Searcher》 的 Xcode 项目 现在 在进行任何与性能相关的分析之前 我们应该做的一件重要事情 是在 Xcode 中选择“Profile”Scheme 这将确保 Xcode 在发布模式下重新编译你们的 App 以便你们可以利用编译器时间优化
一旦 Xcode 重新编译你们的 App 它将在你们的设备上安装它 并启动 Instruments 现在我们很高兴地宣布 从 iOS 13 或 Xcode 11 开始 我们现在有了 App Launch 模板 专门用于这样的情况 弄清楚 App 启动的问题 那么 让我们继续并 双击 App Launch 现在我们要做的 第一件事就是点按记录按钮
此时 Instruments 将自动 启动我们的 App《Star Searcher》 收集所有指标 遥测数据 分析它们 并为所有 App 启动阶段 创建可视化 所以 看一看 标记为紫色的 前几个阶段是 在 App 中调用 main 函数 之前发生的阶段
在绿色阶段 当你们的 App 完成其启动 并在 UI 中绘制其第一帧 早期的这些过程发生在 你们的主要功能的 第一阶段 让我们继续并展开轨道 在我们展开轨道时 你们可以看到在 App 进程中 响应的所有线程的 详细状态 显然 最重要的一个 是主线程 或者也称为 UI 线程 它负责处理 用户输入和绘制 UI 让我们继续并确定 与我们的目的相关的轨道 从 App 启动阶段开始 我们的主要线程 还有一个工人线程 在启动期间 做了大量的工作 所以 让我们继续下去 并将其 固定下来
说到线程状态 哎呀 像那样
说到线程状态 灰色意味着它被阻止 这意味着线程没有做任何工作
红色意味着它可以运行 这意味着计划完成工作 但缺乏 CPU 资源 橙色意味着它被抢先一步 这意味着它正在开展工作 但却被中断 支持其他具有更高优先级的竞争工作 最后但并非不重要的是 蓝色表示它正在运行 这意味着它实际上正在 CPU 核心上工作 因此 有了这些信息 让我们从系统界面初始化 开始逐步查看
如果我们点按一个阶段三次 我们可以突出显示这个阶段 并在屏幕下半部分 获取详细信息 在你们的左侧 你们可以看到在此时间段内 正在完成的所有工作的 详细栈跟踪 在右侧 你们也可以看到 聚合栈跟踪 其中列出了按 CPU 样本数量排序的所有符号 现在请注意这个初始阶段 在设置系统接口时只需要 6 毫秒 这主要归功于 dyld3 的引入 和第三方应 App 的优势 以及其他系统层的增强功能 因此 作为开发者 我们可以利用所有这些 增强功能 而无需编写任何代码 让我们继续来看 但在我们这样做之前 我还应该指出另一件事
请注意 虽然此阶段 仅为《Star Searcher》 的 CPU 占时上花费了 6 毫秒 但它实际上花费了 149 毫秒 这种差异来自 分析机制本身的开销 它确实为我们 提供了大量的信息和想法 但是它有自己的成本 因此 这就是将分析与 测量结果区分开来 非常重要的原因 稍后我将对此进行解释 进入下一阶段 即静态运行时初始化 现在我们注意到这个阶段 耗时惊人的 375 毫秒 这就有点太长了
那我们来看看吧 查看详细的栈跟踪 我们看到一个带有 蓝色图标的突出显示的符号 标志着 CPU 工作量为 370 毫秒 现在 所有这些突出显示的 符号表示在我们的 源中声明的代码 我们来点按它
现在通过扩展栈跟踪 它将我们指向 SLSuperFastLogger 现在 如果一个库自称超高速(SuperFast) 是有一些可疑的 但还是让我们来看看 那么 SLSuperFastLogger 是我们专门导入 《Star Searcher》的外部框架 可以利用强大而方便的日志记录 但是 我们调用此框架的 唯一位置是 在 TableViewController 中 具体说来 在 didSelectRowAt 回调中
现在这个回调完全在 启动路径之外 因为它只在用户点按 一个单元格时调用 那么 为什么它在之前的启动期间 甚至在我们的主函数被调用之前 它的工作量超过 300 毫秒呢 好吧 我们来探个究竟
通过搜索符号 它指向我们在 SLSuperFastLogger 类中 声明的加载方法 现在 这是一个 静态初始化程序 这意味着所有这些工作 都将在调用 main 函数之前的 早期启动时完成 因为我们链接了它 这里的重点是 了解依赖在你们使用的 框架中的影响 是非常重要的 外部库和框架可能很方便 也可能很强大 但可能需要付出 巨大的代价 所以 如果这些成本带来了 这些好处 那很好 但对于我们的情况 在启动期间的 300 毫秒 对于它的价值来说有点花费太多了 所以 让我们继续前进 寻求替代方案
在我们的例子中 让我们使用 os.log 这是一个非常轻量级 和高效的日志记录机制 适用于 iOS 以及 其他 Apple 平台 一旦我们删除了依赖 我们一定要记住一件事 即删除实际的链接 现在因为这里的成本 是静态初始化程序 我们需要确保删除链接 以免影响我们 那么 有了这个 让我们回到我们的跟踪
下一阶段是 UIKit 初始化 实际上耗时 28 毫秒 这几乎是所有 App 的固定成本 除非你们将 UI App 子类化 或在 UIApplicationDelegate 中执行 自定义初始化工作 否则它几乎是我们 现在可以忽略的 那么 让我们继续前进
下一部分工作是 你们的 App 初始化 这基本是由你们控制的 注意到使用 didFinishLaunchingWithOptions 回调进行了大量的工作 这在时钟上花费了 791 毫秒 这其实很长 让我们来看看 因此 此阶段立即 指出我们在 StarDataProvider 类中进行了大量工作
也就是在载入星星 好的 现在请注意主线程中 存在巨大的阻塞 这实际上是我们启动的延迟 我们的主线程被阻止了 754 毫秒 这很不理想
让我们来看看
因此 为了检查详细状态 我们应该查看事件列表
通过查看事件列表 我们注意到它被 阻止了 754 毫秒 之后 它被线程 0x12253 解除阻塞 或者说变得可运行了 这对应着正在做大量工作的工人线程
所以 这里有一些联系
现在回到主线程 注意它被安排 在优先级 47 上工作 47 个等同于 用户交互 QoS 现在注意到这些红色交汇处 我们还有很多工作要做 但是他缺少 CPU 资源 好吧 让我们找出原因
当我们点按工人线程时 我们注意到有 很多工作计划在 优先级 4 下工作 这相当于后台 QoS 我们在这里 实际看到的是一种被称为 优先级倒置的问题 其中给定线程被一个比自身 具有更低 QoS 或优先级的 单独线程阻塞 显然 这并不理想 因为它占用的资源 超出了应有的范围 所以 让我们继续尝试解决这个问题 回顾一下这个问题的核心 StarDataProvider 是一个 非常简单的类 它负责从 SQLite 数据库 中获取我们的星星数据 有一个具有 后台 QoS 的专用调度队列 并注意这是 为了确保数据提取 不会与 UI 竞争 并且有两个 API 被暴露 一个用于使用 此 GrandCentralDispatch 的异步原语 和另一个以同步方式加载数据的同步 API
现在看看 didFinishLaunchingWithOptions 中的实际调用站点
我们正在利用 异步 API 但也利用调度 semaphore 来确保在继续 绘制 TableView 的第一帧之前 等待所有数据都被提取 现在 如果我们要这样做 我们应该使用正确的并发原语 也就是 GCD 中的同步原语 用过使用正确的并发原语 GrandCentralDispatch 将 临时将主线程 的优先级传播到 工人线程 并将其提升为 用户非活动状态
以使其匹配 所以 在这一点上 我认为我们有可能 解决优先级倒置问题 但我还注意这儿 有一个问题
loadStarDataSync API 接受 一系列行来加载数据 在我们的例子中 我们从第 0 行加载到最后一行 这基本上就是一切 现在 当你们考虑它时 第一帧只能适合 可能在屏幕尺寸上的 有限数量的单元格 在《Star Searcher》的情况下 可能大约 10 到 15 个 具体取决于设备 所以 让我们继续并优化它 而不是加载所有内容 让我们只加载前 20 行 就足以以同步方式 绘制 TableView 的第一帧 之后 我们应该在后台 懒加载所有其余的 只在启动后完成后 更新 TableView
让我们继续吧 最后但也很重要的是回到追踪 最后一个阶段是我们的 第一个帧渲染
请注意 这个阶段花了 951 毫秒 这是非常长的 考虑到这只是负责 布局工作和我们 第一帧的渲染
现在让我们更深入地了解它 它指向 StarTableViewController
并查看详细的栈跟踪 我们看到了很多工作和 一个 cellForRowAt 回调 它负责执行单元格的布局工作 让我们继续并扩展我们所说的 当我们扩展栈跟踪时 它指明我们为 StarDetailViewController 进行了 大量的初始化工作 这在 CPU 上耗时 882 毫秒 所以 在这一点上我们已经发现 这几乎是这里的瓶颈
我们来看看我们的代码吧 现在查看 cellforRowAt 回调中的 tableView 控制器 我们使用自定义单元格创建单元格
同时 我们进行推测性优化 预热和缓存 DetailView 的 DetailViewControllers 就像我们做布局工作一样 这是希望简化从 表格视图到 详细视图的过渡 但正如我们在追踪中所看到的 这并不会产生高成本
现在退一步 当你想到它时 详细的视图对 我们的第一帧没有意义 只有当用户点按 一个单元格时才有意义 所以 让我们继续推迟这项工作
我们应该把它推迟到哪里 也许是 didSelectRowAt 回调这里 当用户点按一个单元格时调用它
因此 此时 我们对 《Star Searcher》进行了 一些改进或优化 所以 让我们继续并重新分析它
现在需要注意的一点是 当你们进行增量更改时 你们应该在进展时 不断重新测量 和重新分析 这样 你们就可以 真正了解你们增量变更集的确切影响 但是为了这个演示 我们实际上因为 节省时间 把所有变化合并为一个 Boom 有一点 UI 故障 但我们可以立即看到 我们的启动时间不到 500 毫秒 现在 正如我之前所说 分析机制确实带来了 自己的成本 因此 为了更好地了解 我们的用户将 体验到什么 让我们继续使用 新的 XCTest API 来测量 我们测试中的启动性能
只需几行代码 我们就可以将 启动性能测试 或任何性能测试与 XCTest 集成在一起 让我们继续 并启动测试
现在 XCTest 将进行一次一次性的启动测试 这将取消冷启动 会产生的差异 之后 它将执行 指定的迭代次数 或者默认执行 五次迭代 并测量所花费的时间 之后 它将产生一些 很好的统计数据 这项测试需要几分钟才能完成 现在我们已经将《Star Searcher》的启动 从 2.5 秒推到了 刚刚超过 300 毫秒 为了结束演示 我想向你们展示 UI 上的实际情况 好了 让我们确保漂亮得完成了 《Star Searcher》真的很快
谢谢你们 交回给你 Spencer
多谢 Dan 关于如何使用 Xcode Instruments App Launch 模板 来改善我们的 App 启动体验的精彩演示 好的 我们意识到 在你们的代码库中 你们不会在代码中 找到几个可以用几行修复的地方 并获得如此重大的改进
你很可能必须找到一堆 5 到 10 毫秒的胜利 然后将所有这些组合在一起
我们想让你们知道 我们已经在背后支持你们了
我们已经进行了 大量的 iOS 优化以改善 你们的 App 的推出 并帮助你们实现目标 而你们几乎没有采用
我想特别呼吁采用一些 如前所述 dyld3 将运行时依赖项 缓存到你们的 App 中 你们在演示中看到了这些依赖项 这提供了巨大的改进 排程器还经过优化 以帮助确定启动期间 发生的工作的优先级 我们还仔细看了 Auto Layout 和 Objective-C 并在那里进行了一系列优化
最后 我们将在今年晚些时候 对 App 打包进行 激动人心的更改
我们认为这些变化 总会导致你们几乎没有 采用优化的 App 的大幅改进 所以 让我们总结 一些提示和技巧 了解如何在完成 所有这些工作后确保你们的 App 令人愉悦
首先 不要让性能 成为事后的想法 你们应该在每个 Bug 修复的开始 每个参数改动的开始 以及每个功能研发的开始时 考虑并研究它
这是因为 引入回归非常容易 特别是像 2 毫秒这样的小回归 问题是这些小问题 加起来是一个大问题 如果你不立即解决它们 就很难找到它们 为了做到这一点 为了要检测这些回归 你们应该定期绘制 App 的启动 并定期运行测试 这将确保你们达到目标 并立即知道你们 是否已回归了该目标 你们还应该看看 新的 Xcode 管理器 它可以让你们了解 你们 App 在现场的表现
在 iOS 13 中 对于已选择加入的用户 将收集有关你们 App 的 耗电和性能指标
然后 它们将在 24 小时内汇总 并发送回你们的组织者 你们可以通过软件版本和设备版本 以直方图的形式查看它们
但是 如果你们希望 对该数据进行更多控制 你们可以采用 MetricKit
MetricKit 允许你们 指定自定义功率和性能指标
现在 与组织者一样 这些数据将在 24 小时内收集和汇总 然后通过你们 App 中的授权方法 传回给你们 从那里开始 你们就可以 随意处理数据
要了解更多相关信息 我们建议你们查看 2019 年 WWDC 中的 提升电池寿命和性能
那么 总而言之 我们今天非常开心 通过 Xcode Instruments 中的新 App Lauch 模板开始 了解你们 App 的启动 看看你们是否能 找到最小化 最优排序和 优化你们工作的机会
接下来 虽然意图很好 但并非所有优化都能成功得到 例如 Dan 在他的演示中 提到的预热 DetailView 控制器
因此 每当你们进行更改时 请务必测量而不是 大致估计性能 再说一次 无意中 引入回归 非常容易
最后 你们应该 在开发的所有阶段 跟踪你们的表现
这意味着在各种设备上 使用新的 XCTest App 启动测量 并可能将其与 持续集成相结合
这将确保你们 始终为所有设备上的所有用户 提供令人愉快的 App 启动
有关更多信息 请查看我们今天 引用的会议 然后在周五下午 好好休息一下 多谢你们 [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。