iOS学习笔记之App启动速度优化与监测

简述

App启动速度是用户对于App的第一印象,如果App启动的很慢非常有可能导致用户的流失。

在开发过程中和实际生活过程中,我们都会经常遇到这类的话题。
在工作中的时候,运营小伙伴会说我们的开发技术不如竞品,判断依据是什么呢?别人启动速度比我们的快好几倍。

在实际生活过程中,我们可能会依赖于各种各样的App,而这些App不乏缺少竞品,为什么我们会在芸芸众生中选择其中某一款呢?除了功能外启动速度也成了我们衡量的一种标准。

正文

App启动分类

  • 冷启动

App启动前没有所以该App的进程在系统中,用户从点击App的icon那一刻开始到用户看到第一个页面,这一完整的启动过程。

  • 热启动

App在冷启动之后,用户点击Home或者其他方式将App切入到后台,这时候App不会被系统立马释放屌,还会继续存活若干时间,这个时候App的进程还在系统中,这种情况下,用户重新启动App的过程。

App启动过程

一般而言,App的启动主要有三个阶段:

  • main()函数执行前
  • main()函数执行后
  • 首屏渲染完成

main()函数执行前

  1. 加载可执行文件(App 的.o 文件的集合);
  2. 加载动态链接库,进行rebase指针调整和bind符号绑定;
  3. Objc运行时的初始处理,包括Objc相关类的注册、category注册、selector唯一性检查等;
  4. 初始化,包括了执行+load()方法、attribute(constructor)修饰的函数的调用、创建C++静态全局变量。

main()函数执行后

main()函数执行后的阶段,指的是从main()函数执行开始,到AppDelegatedidFinishLaunchingWithOptions方法里的首屏渲染相关方式执行完成。

首屏的业务代码都是要在这个阶段,也就是首屏渲染前执行的,主要包括了:

  • 首屏初始化所需要的一些配置文件的读写操作;
  • 首屏列表数据的读取;
  • 首屏渲染的一些计算等。

首屏渲染完成

  • 非首屏其他业务服务模块的初始化;
  • 其他业务基础功能初始化;
  • 监听的注册;
  • 配置文件的读取等。

App启动速度优化方案

针对main()函数执行前的优化

  1. 苹果公司建议使用更少的动态库,并建议在使用动态库的数量较多时,尽量将多个动态库进行合并。数量上,苹果公司最多支持6个非系统动态库合并为一个,减少动态库的加载;
  2. 减少加载启动后不会去使用的类或方法;
  3. +load()方法里的内容可以放到首屏渲染完成后在执行,或者使用+initialize()方法替换掉。每一个+load()方法里,进行运行时方法替换操作会带来4毫秒的消耗;
  4. 控制C++全局变量的数量。

针对main()函数执行后的优化

梳理出哪些是首屏渲染必要的初始化功能,哪些是App启动必要的初始化功能,哪些是只需要在对应功能开始使用时才需要初始化的,在梳理完之后将一些初始化功能放到对应的合适阶段中进行。

针对首屏渲染完成后的优化

这一部分主要是针对一些会卡住主线程的方法。

功能级别的优化

优化思路:main()函数开始执行后到首屏渲染完成前,只处理首屏相关的业务,其它非首屏业务的初始化、监听注册、配置文件读取等都放到首屏渲染完成后去做

方法级别的优化

优化思路:检查首屏渲染完成前,主线程上还有哪些耗时方法,将没必要的耗时方法滞后或异步执行。

App启动速度的优化监控方案

定时抓取主线程上的方法调用堆栈,计算一段时间里的各种方法的耗时

利用Xcode工具自带的Time Profiler

优点:开发成本低,IDE自带

缺点:精度低,定时间隔设置时间长的话,会漏掉一些方法,导致检查出来的耗时不精确,定时时间间隔设置的时间短,抓取堆栈方法本身调用也会影响整体耗时,导致结果不精确。

objc_msgSend方法进行hook来掌握所有方法的执行耗时

即在原方法开始执行时,换成其他指定的方法,或者在原有方法执行前执行指定的方法,来达到空我和改变指定方法的目的。

优点:非常精确

缺点:只能针对Objc的方法,如果是针对C方法和block可以使用libffiffi_call来完成,但是便携和维护相关工具的门槛比较高。

相关工具:
Facebook 开源了一个库fishhook,可以在 iOS 上运行的 Mach-O 二进制文件中动态地重新绑定符号。

你可能感兴趣的:(iOS学习笔记之App启动速度优化与监测)