一般而言,大家把iOS冷启动的过程定义为:从用户点击App图标开始到appDelegate didFinishLaunching方法执行完成为止。这个过程主要分为两个阶段:
- T1:main()函数之前,即操作系统加载App可执行文件到内存,然后执行一系列的加载&链接等工作,最后执行至App的main()函数。
- T2:main()函数之后,即从main()开始,到appDelegate的didFinishLaunchingWithOptions方法执行完毕。
然而,当didFinishLaunchingWithOptions执行完成时,用户还没有看到App的主界面,也不能开始使用App。例如App还需要做一些初始化工作,然后经历定位、首页请求、首页渲染等过程后,用户才能真正看到数据内容并开始使用,我们认为这个时候冷启动才算完成。我们把这个过程定义为T3。
pre-main time的过程
1 dylib loading time
载入动态库,这个过程中,会去装载app使用的动态库,而每一个动态库有它自己的依赖关系,所以会消耗时间去查找和读取。对于Apple提供的的系统动态库,做了高度的优化。而对于开发者定义导入的动态库,则需要在花费更多的时间。
2 rebase/binding time
重构和绑定,rebase会修正调整处理图像的指针,并且会设置指向绑定(binding)外部的图像指针。所以为了加快rebase/binding,则需要更少的做指针修复。当你的app当中有太多的Objective-C的类,方法选择器,和类别会增加这一部分的启动时间。
3 ObjC setup time
在Objective-C的运行时(runtime),需要对类(class),类别(category)进行注册,以及选择器的分配。
4 initializer time
是执行+initialize方法的时间。
综上,冷启动过程定义为:从用户点击App图标开始到用户能看到App主界面内容为止这个过程,即T1+T2+T3。在App冷启动过程当中,这三个阶段中的每个阶段都存在很多可以被优化的点。
从T1流程中,我们可以做优化的点主要有
1.是减少系统依赖库
2.减少自己需要加入的各种三方库(库越少dyld加载的速度越快,就能越早的返回程序入口main函数的地址)
3.有一些自己加入的库,能选择静态库就选择静态库,少用动态库,因为动态库的加载方式比静态库慢。如果必须依赖动态库,则把多个非系统的动态库合并成一个动态库。
4.自己加入的各种framework库根据情况设为optional和required,如果该framework在当前App支持的所有iOS系统版本中都存在,那么就设为required,否则就设为optional,因为optional会有些额外的检查会导致加载变慢。
5.将不必须在+load方法中做的事情延迟到+initialize中,尽量不要用C++虚函数(创建虚函数表有开销)。
6.减少项目文件中Category,静态变量等的使用数量
7.检查项目中,那些类和方法没有使用到。 把没有使用到的删除
8.让UI大佬尽量把给的资源压缩到最小,因为在启动加载时会加载资源图片进行IO操作。所以图片小加载速度也会响应提升。
9.内存上优化:类和方法名不要太长:iOS每个类和方法名都在__cstring段里都存了相应的字符串值,所以类和方法名的长短也是对可执行文件大小是有影响,及影响加载速度也消耗内存;因为OC的动态特性,都是加载后通过类/方法名反射找到这个类/方法进行调用,OC的对象模型会把类/方法名字符串都保存下来(压缩算法TinyPNG)。
10使用更多的Swift代码
从T2流程中,我们可以做优化的点主要有
1不使用xib,直接视用代码加载首页视图。
2每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对Debug版输出log。
3将可以延时处理的SDK移到后面执行。
4将首页viewDidLoad中网络请求,数据解析,视图渲染等耗时操作移到viewDidAppear中执行。
延展:插件式启动项注册,去中心化。