前言:一般来讲,app的启动时间是用户点击app图标到看到第一个界面的时间差,如果启动时间太慢,就会极大的影响到用户体验,所以对启动时间进行优化是个很有必要的操作。
一.Define
首先看看苹果的标准:
Apple suggest to aim for a total app launch time of under 400ms and you must do it in less than 20 seconds or the system will kill your app.
建议应用的启动时间控制在400ms之下,并且在20s内启动,否则系统会kill app。
我们知道app的入口是main函数,但在main函数之前app会做很多系统级别的准备,这部分的操作所消耗的时间叫pre-main time。在执行main函数后,调用AppDelegate中的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法完成初始化,并展示首页,到此方法结束,这部分所消耗的时间为main time。所以有:
T(App启动时间)= pre-main time + main time;
启动时间优化也是对这两部分的时间进行优化。
二.Measure
优化之我们需要测量两部分的时间,找出最耗时的操作,然后进行优化。
1.pre-main time测量。
在Xcode中的Edit Scheme -> Run -> Argument
,设置参数DYLD_PRINT_STATISTICS
值为YES。然后运行工程,控制台打印如下:
Total pre-main time: 916.28 milliseconds (100.0%)
dylib loading time: 159.62 milliseconds (17.4%)
rebase/binding time: 552.85 milliseconds (60.3%)
ObjC setup time: 66.35 milliseconds (7.2%)
initializer time: 137.31 milliseconds (14.9%)
slowest intializers :
libSystem.dylib : 3.14 milliseconds (0.3%)
CSleepDolphin : 164.47 milliseconds (17.9%)
2.main time测量。
这部分我们用到自定义的工具,在具体代码下埋点,记录相关代码的执行时间和总时间。控制台打印如下:
#1 configHttp: 0.000
#2 configLog: 0.002
#3 publicModuleConfig: 0.038
#4 MagicalRecord: 1.011
#5 window: 0.193
#6 configUMeng: 0.008
#7 diplomatConfig: 0.944
#8 RemoteNotification: 0.006
#9 LocalNotification: 0.001
#10 configBugly: 0.000
#11 hookSetup: 0.003
#12 clockRemote: 0.008
#13 configYouZan: 0.442
#14 HETH5Manager: 0.002
#15 appUpdate: 0.001
#16 didFinishLaunchingWithOptions: 2.659
#17 viewDidLoad: 0.049
#18 viewDidLoad-config: 0.016
#19 viewDidAppear: 2.809
三.Analysis
1.对pre-main time的分析
1.1 dylib loading time
载入动态库,这个过程中,会去装载app使用的动态库,而每一个动态库有它自己的依赖关系,所以会消耗时间去查找和读取。对于Apple提供的的系统动态库,做了高度的优化。而对于开发者定义导入的动态库,则需要在花费更多的时间。
1.2 rebase/binding time
重构和绑定,rebase会修正调整处理图像的指针,并且会设置指向绑定(binding)外部的图像指针。所以为了加快rebase/binding,则需要更少的做指针修复。当你的app当中有太多的Objective-C的类,方法选择器,和类别会增加这一部分的启动时间。
1.3 ObjC setup time
在Objective-C的运行时(runtime),需要对类(class),类别(category)进行注册,以及选择器的分配。
1.4 initializer time
是执行+initialize方法的时间。
2.对main time的分析
从控制台打印可以看出,部分代码耗时比较严重,最高有0.944s(第三方登录)。我们把didFinishLaunchingWithOptions中的方法分为几个部分:
- 优先配置:日志、统计等
- 必须配置:项目配置、环境配置、用户信息的初始化 、推送
- 可延时配置:工具类等
四.Improve
1.对pre-main time的优化
- 尽量少的使用自定义的动态库,或者考虑合并多个动态库,其中一个建议是当大于6个的时候,则需要考虑合并它们。
- 合并或者删减一些OC类,关于清理项目中没用到的类
- 移除静态的初始化操作
- 删减没有被调用到和已经废弃的方法,合并功能相同的分类(从控制台打印可以看到
rebase/binding time: 552.85 milliseconds (60.3%)
耗时严重,需减少不必要的类,分类,方法,从而减少指针修复) - 将不必须在+load方法中做的事情延迟到+initialize中
- 尽量不要用C++虚函数(创建虚函数表有开销)
- 使用更多的Swift代码
2.对main time的优化
- 不使用xib,直接视用代码加载首页视图。
- 每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对内测版输出log。
- 将可以延时处理的SDK移到首页viewDidAppear中执行。
- 将首页viewDidLoad中网络请求,数据解析,视图渲染等耗时操作移到viewDidAppear中执行。
五.Control
定期对项目进行启动时间测量及精简代码。
网友评论