iOS App性能优化——启动时间优化

前言:一般来讲,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
  • Objc的+load()函数
  • C++的构造函数属性函数
  • 非基本类型的C++静态全局变量的创建(通常是类或结构体)

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

定期对项目进行启动时间测量及精简代码。

你可能感兴趣的:(iOS App性能优化——启动时间优化)