iOS关于启动时间的检测及优化

启动时间

启动时间可谓是用户对你的App的第一印象,用户好不容易下载了App,然后饶有兴致的开打App,启动时间过长很可能会让用户直接把App打入冷宫。就算用户非常有耐心,苹果的watch dog机制也会kill掉启动时间过长的App,这种情况下给用户的感觉就是这App怎么一启动就卡死然后崩溃了,然后无情卸载。这里还要说一下,Xcode在debug模式下是没有开启watch dog的,所以不要以为调试时候没问题就真的没问题了,一定要在真机上测试一下。

首先我们了解一下App的启动流程
App启动流程图
通过实际的调试,我们得到各个函数的调用顺序如下:

  1. 启动页
  2. main()
  3. UIApplicationMain()
  4. willFinishLaunchingWithOptions()
  5. didFinishLaunchingWithOptions()
  6. loadView()
  7. viewDidLoad()
  8. applicationDidBecomeActive()
    启动页是在main()函数调用之前出来的,main()是程序的入口,里面调用了UIApplicationMain()。当App从didFinishLaunchingWithOptions()返回的时候,实际的UI立刻开始加载,但是在applicationDidBecomeActive()这个回调完成之前,UI即使已经初始化,但仍旧被阻塞着。

总的启动时间T包括main()调用之前的pre-main timeT1,加上从main()applicationDidBecomeActive()的时间T2。

获取启动时间

我们可以通过环境变量的方法来获取pre-main time。打开Xcode->Product->Scheme->Edit Scheme或者直接command+shift+<(在键盘上是逗号,按住shift就是小于号了)。在Edit Scheme中添加DYLD_PRINT_STATISTICS这个环境变量,如果要打印详细的时间分布,可以将value设为1
Edit Scheme
运行项目之后就会在控制台会打印出每个阶段都耗时多少
在这里插入图片描述
dylib loading time:加载动态库
rebase/binding time:修正指针和数据。此外,因为Objc是一种动态语言,因此需要注册类名与类相关信息的一张注册表,对在其他dylib中定义的category,也需要通过rebasing和binding来修正扩展方法的地址来保证selector的唯一性。关于rebase/binding 这块,有兴趣的小伙伴可以看看这篇文章
ObjC setup time:ObjC类初始化
initializer time:其他初始化,如上图,细分为其他的几个部分
libMainThreadChecker:debug时候检查线程的
了解完毕mian()函数之前加载的步骤后,我们可以简单的分析出影响T1时间的各种因素:

 1. 动态库加载越多,启动越慢
 2. ObjC类,方法越多,启动越慢
 3. ObjC的+load越多,启动越慢
 4. C的constructor函数越多,启动越慢
 5. C++静态对象越多,启动越慢

我们已经获取到了main()函数之前的启动时间T1,至于T2,我们可以使用Xcode自带工具Instruments里面的Time Profiler来获取,也可以在main()的第一句和applicationDidBecomeActive()的最后一句加上获取时间的代码CFAbsoluteTimeGetCurrent(),这里就不细说了。

Time Profiler

工具通过Xcode工具栏中Product->Profile(command+i)可以启动,(也可以通过Xcode->Open Developer Tool->Instruments)启动后界面如下:
Instruments
选择Time Profiler,打开后如图:
Time Profiler
点击左上角红色按钮运行,勾选左下角Call TreeSeparate ThreadHide System Libraries,等到第一个页面显示出来的之后,点击左上角暂停按钮,下面就会统计出每个步骤的耗时情况。这个时候我们就可以很容易得到启动时间T2。

优化启动时间
针对T1的各个阶段分别进行优化处理

1.dylib loading time

  • 核心思想是减少dylibs的引用
  • 合并现有的dylibs
  • 使用静态库

2.rebase/binding time

  • 核心思想是在进行动态库的重定位和绑定(Rebase/binding)过程中减少指针修正;
  • 减少Objective-C类数量,减少分类,减少实例变量和函数(删除不用的类以及冗余代码,再深一点就是减少第三方工具的使用,可以查看源码,自己实现);
  • 减少C++虚函数;
  • 多使用Swift结构体(推荐使用swift)

3.ObjC setup time
核心思想同上,主要是类的注册,分类的注册,唯一Selector。这部分内容基本上在上一阶段优化过后就不会太过耗时。

4.initializer time

  • 使用initialize替代load方法
  • 减少使用c/c++的attribute((constructor));推荐使用dispatch_once(),pthread_once(), std:once()等方法
  • 不要在初始化中创建线程
  • 推荐使用swift
针对T2进行优化

我们通过Time Profiler拿到每个步骤的耗时之后,右下角的 Heaviest Trace 可查看比较消耗CPU的代码,双击点击进去可查看到对应的代码,进行修改。有些操作可以延后执行,或者异步执行等,这些需要根据自己的业务逻辑在处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值