一、 APP 启动类型
APP启动分为 冷启动
、热启动
两种
冷启动
:
APP的icon从点击启动前,它的进程不在系统里,需要新创建一个进程分配给它的启动的情况。热启动
:
APP在启动后用户将APP退到后台,在APP的进程还在系统里的情况下,用户重新启动进入APP的过程。(这个过程做的事情比较少)
二、APP启动的三个阶段、
pre-main ( main()函数启动之前)
main() 函数之后启动之后
首屏渲染完成
1、pre-main
: ( main()函数启动之前)
此步骤是启动第一步,主要包括四个步骤:
- 加载动态库耗时 (
dylib loading
):- 修正符号和绑定符号耗时 (
rebase/binding
)- OC类注册 耗时(
ObjC setup time
)- +load()函数耗时 (
initializer
)
这几个步骤的耗时,我们可以通过配置环境变量打印出来进行查看:
- 首先我们进入
Edit Scheme
,然后选中Run -> Arguments -> Environment Variables
- 然后配置
key
为:DYLD_PRINT_STATISTICS
- 然后我们启动项目,就会发现xcode会打印出
pre-main
的耗时,每个小步骤的耗时都会显示出来:
下面我们分析下每个小步骤的主要功能:
dylib loading
:
主要是载入动态库,这个过程会去加载APP使用到的所有动态库,而动态库之间有自己的依赖关系,所以会消耗时间去查找和读取。
优化
:
尽量使用系统库
: 因为系统的动态库已经做了优化尽量减少动态库的使用
: 动态库使用尽量不要超过6
个,如果超过,最好去合并他们使用将动态库替换为静态库使用
:静态库的使用会简化时间
rebase/binding
:
rebase
:内部调整指针的指向,Mach-o被加载到内存的时候会添加随机地址(ASLR),这个随机的地址跟代码和数据指向的旧地址会有偏差。dyld 需要修正这个偏差,做法就是将 dylib 内部的指针地址都加上这个偏移量。
binding
:将指针指向镜像(MachO文件)外部的内容,binding就是将这个二进制调用的外部符号进行绑定的过程。
优化:
Objc setup
:oc 类的加载
1、读取二进制文件的 DATA 段内容,找到与 objc 相关的信息
2、注册 Objc 类,ObjC Runtime 需要维护一张映射类名与类的全局表。当加载一个 MachO 时,它定义的所有的类都需要被注册到这个全局表中;
3、读取 protocol 以及 category 的信息,把category的定义插入方法列表 (category registration)
优化:
尽量减少类的使用
:有的地方可以用结构体替代
删除无用、废弃的类
initializer
: 函数初始化
1、Objc的 +load()函数调用
2、C++
的构造函数的调用
优化:
尽量减少在+load()
里面添加放法,减少+load()
函数的复杂度
尽量不要用C++虚函数
2、main函数阶段的优化
在main
函数之后主要是执行didFinishLaunching
方法,这个方法主要是执行各种业务。但是有些任务不需要立即执行,这时候我可以对其采取延迟加载,减少对启动时间的影响。
主要的业务主要分三类:初始化第三方SDK
、环境配置
、自己的工具栏的初始化
,针对这三大类进行优化:
减少启动初始化流程
: 针对一些方法流程,能懒加载的懒加载,能延迟的延迟执行,尽量少占用主线程的启动时间能使用多线程来初始化的,就使用多线程
尽量避免使用xib/SB搭建UI,最好使用纯代码搭建
删除废弃的类、方法等
3、首屏加载的优化
上面的两种优化方法,在小项目中都是毫秒级的,能优化的空间不到,效果有时候用户根本看不出来,用户能感知的是从点击图标到应用首页加载出来的整个过程,所以这时候首屏的优化就显得很重要了,这里大致说下首屏优化的几个方面:
- 从本地回去缓存数据加载
此方法适合,首页数据不需要及时更新的情况,我们可以把上一次请求到数据缓存在磁盘或者数据库中,启动的的时候,直接从磁盘中加载,加载完成之后再去请求网络数据,这时候如果数据不一样就刷新界面,并重新缓存数据,以待下次使用
- 使用骨架屏
这个适合需要展示实时性比较高的情况,我们在网络请求的时候,去展示骨架屏,给用户一个数据即将出来的感觉
- 拆分请求接口
- 这种情况适合,首页展示多模块的数据,且模块之间的依赖性比较弱的情况。
- 我们把每个模块的数据请求都放在子线程去处理,数据响应后在子线程完成相关的数据预处理,然后去主线程渲染,这样就把数据分开来,哪个数据先回来,先去渲染哪个模块
- 当然,有时候我们没必要一次请求所有的模块数据,如果一个模块的数据,不会在第一屏显示,需要在滑动后才能看到的时候,我们就可以对此模块的数据进行延迟请求,用到的时候才去请求渲染
- 延迟其他信息配置服务
- 对于用到的第三方服务,我们可以延迟几秒,放在渲染完成之后去配置
- 对于有时候首页我们需要去获取升级信息或者一些其他的配置,也可以放在渲染之后再去请求配置