APP启动优化

参考转自:
https://mp.weixin.qq.com/s?__biz=MzA5NzMwODI0MA==&mid=2647761916&idx=1&sn=b7f1f7e6b1f44be64a106f94e0000c56&chksm=8887d8c3bff051d5b0ccabaf620e334a93e22339d920ddd5ceb19a794541ad741b8f50641614&scene=21#wechat_redirect

https://tech.meituan.com/waimai_ios_optimizing_startup.html
https://blog.csdn.net/guojin08/article/details/48527743

重要性

如今在注重性能的环境下,app启动时间首先是考研一个app好坏的最直观的表现。

冷启动定义

一般而言,大家把iOS冷启动的过程定义为:从用户点击App图标开始到appDelegate didFinishLaunching方法执行完成为止。这个过程主要分为两个阶段:

  • T1:main()函数之前,即操作系统加载App可执行文件到内存,然后执行一系列的加载&链接等工作,最后执行至App的main()函数。
  • T2:main()函数之后,即从main()开始,到appDelegate的didFinishLaunchingWithOptions方法执行完毕。
image

然而,当didFinishLaunchingWithOptions执行完成时,用户还没有看到App的主界面,也不能开始使用App。例如在外卖App中,App还需要做一些初始化工作,然后经历定位、首页请求、首页渲染等过程后,用户才能真正看到数据内容并开始使用,我们认为这个时候冷启动才算完成。我们把这个过程定义为T3。

image

综上,外卖App把冷启动过程定义为:从用户点击App图标开始到用户能看到App主界面内容为止这个过程,即T1+T2+T3。在App冷启动过程当中,这三个阶段中的每个阶段都存在很多可以被优化的点。

1. main函数之前

从dyld开始

动态链接库

image.png

iOS中用到的所有系统framework都是动态链接的,类比成插头和插排,静态链接的代码在编译后的静态链接过程就将插头和插排一个个插好,运行时直接执行二进制文件;而动态链接需要在程序启动时去完成“插插销”的过程,所以在我们写的代码执行前,动态连接器需要完成准备工作。

ImageLoader

当然这个image不是图片的意思,它大概表示一个二进制文件(可执行文件或so文件),里面是被编译过的符号、代码等,所以ImageLoader作用是将这些文件加载进内存,且每一个文件对应一个ImageLoader实例来负责加载。
两步走:

在程序运行时它先将动态链接的image递归加载 (也就是上面测试栈中一串的递归调用的时刻)
再从可执行文件image递归加载所有符号
当然所有这些都发生在我们真正的main函数执行前。

runtime与+load

+load() 函数调用特点如下:

当类被引用进项目的时候就会执行load函数(在main函数开始执行之前),与这个类是否被用到无关,每个类的load函数只会自动调用一次.由于load函数是系统自动加载的,因此不需要调用父类的load函数,否则父类的load函数会多次执行。

1.当父类和子类都实现load函数时,父类的load方法执行顺序要优先于子类
2.当子类未实现load方法时,不会调用父类load方法
3.类中的load方法执行顺序要优先于类别(Category)
4.当有多个类别(Category)都实现了load方法,这几个load方法都会执行,但执行顺序不确定(其执行顺序与类别在Compile Sources中出现的顺序一致)
5.当然当有多个不同的类的时候,每个类load 执行顺序与其在Compile Sources出现的顺序一致

由于调用load方法时的环境很不安全,我们应该尽量减少load方法的逻辑。另一个原因是load方法是线程安全的,它内部使用了锁,所以我们应该避免线程阻塞在load方法中

总结:

优化需要从两个方面,
一方面是main()函数之前,需要减少不必要的依赖库,减少不必要的image source资源,减少load方法使用
另一方面是从代码加载网络资源,逻辑上处理,避免阻塞主线程。

你可能感兴趣的:(APP启动优化)