深入理解 iOS 启动流程和优化技巧 下

1,903 阅读4分钟

点赞再看,微信搜索 【iOS 成长指北】 对全书进行指点。欢迎分享,有任何问题都可以提出 整篇文章过长。所以进行拆分

参考 WWDC2016 - Optimizing App Startup TimeWWDC2019 - Optimizing App LaunchWWDC2017-App Startup Time: Past, Present, and FutureWWDC2016 - Using Time Profiler in InstrumentsWWDC2018-Behind the Scenes of the Xcode Build Process, Apple - Reducing Your App's Launch Time抖音品质建设 - iOS启动优化《原理篇》

Apple 推荐的启动时间(这里指的是冷启动)最好在 400 ms 左右。最大不能超过 20 s,超过 20 s 会被系统杀掉。

这里的启动时间指得是从用户点击应用图标到启动图消失的第一帧。包含 main 函数加载之前和 main 函数加载之后到第一个 ViewController 加载完成时。

收集应用的启动时间

为了更好的评估应用的启动时间,尤其是线上应用的启动时间,我们可以通过打开Xcode的 Window -> Organizer ->Metrics 或者在项目中集成 MetricKit

使用过滤器检查不同设备上的启动时间,以及典型的和最长的时间。

除了启动时间以外,MetricKit 的报告中还有应用的恢复时间。

分析应用程序的启动时间

通过使用 Instruments 的 App Launch, 分析应用程序的启动时间。

关于 App Launch 的具体使用,可以参考 Instruments Help

为了确保获取的启动时间(冷启动)获取的正确性,我们应该重启设备进行分析,而不是单纯的重新打开应用。

如何优化

我们介绍一些简单并且易于实现的方案。所以并不会介绍诸如大厂团队的的基于二进制文件重排的解决方案 APP 启动速度提升超 15% 的具体实现。

main 函数之前

减少内嵌(embedded)的 dylib 文件

加载内嵌(embedded)的 dylib 文件很占时间,所以尽可能把多个内嵌 dylib 合并成一个来加载,或者使用 static archive。不建议使用 dlopen() 来在运行时进行懒加载,这么做可能会带来一些问题,并且总的开销会更大。

减少静态初始化块

iOS 中的静态初始化代码大概包括以下几种

  • C++ 静态构造函数

  • 定义在类或类别中的load 方法

  • 被__ attribute __ ((constructor)) 标记方法,具体有哪些并且怎么用可以查看 黑魔法 __ attribute __((cleanup))

  • 任何直接连接APP或二进制库的__ DATA,__mod_init_func 方法

减少代码中的这些方法的使用,例如 在类或类别中使用+initialize 来代替 load 方法。使用 dispatch_once(), pthread_once()std::once() 来代替方法中的__ attribute __ ((constructor))

减少无用的代码

你编译到应用程序中的每个类都会减慢 rebase/binding 和 Objective-C 初始化的时间,所以去掉那些你不再使用的类。养成重构代码的好习惯,能合并的类就合并,减少结构中的文件。

main 函数之后

合理分配初始化代码

在实际的代码编写过程中,我们经常在 application:didFinishLaunchingWithOptions: 中注册一些比如SDK的使用还是什么的,在这些方法中,只做准备应用程序初始显示所需的工作;在应用程序的生命周期中,将其他任务推迟到更合适的时间。

使用后台线程

首屏第一帧出现之前的绝大部分操作应该将重心放在主线程的UI 上。尽量使用后台线程来处理一些别的什么事。

优化初始视图的层次结构

尽量使用简单或者分布操作的方式来简化首页的样式。甚至可以在首页上盖一个骨架图来替代真实的UI,如果页面过于复杂的话。UI 加载的越快,启动看起来也会越快


欢迎点赞、转发、评论。微信搜索公众号「iOS成长指北」。由于笔者的学习能力和语言表达能力,有任何不清楚或错误的地方欢迎在留言区留言。后续也会对文章进行修改。希望能一起学习,获得成长。希望一起交流