点赞再看,微信搜索 【iOS 成长指北】 对全书进行指点。欢迎分享,有任何问题都可以提出 整篇文章过长。所以进行拆分
参考 WWDC2016 - Optimizing App Startup Time,WWDC2019 - Optimizing App Launch,WWDC2017-App Startup Time: Past, Present, and Future,WWDC2016 - Using Time Profiler in Instruments , WWDC2018-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成长指北」。由于笔者的学习能力和语言表达能力,有任何不清楚或错误的地方欢迎在留言区留言。后续也会对文章进行修改。希望能一起学习,获得成长。希望一起交流