一般而言,ios启动过程是从用户点击App图标开始到appDelegate didFinishLaunching方法执行完成为止。以main()函数的调用为界限可将启动过程分为两步:main函数之前:即操作系统加载App可执行文件到内存,然后执行一系列的加载&链接等工作,最后执行至App的main()函数和main函数之后:main()函数之后,即从main()开始,到appDelegate的didFinishLaunchingWithOptions方法执行完毕。
main函数之前
这段时间主要是从在屏幕上点击应用到开始执行main方法这段时间,
主要是系统环境布局:创建进程、加载解析可执行文件(库加载、堆栈环境配置等等)。其中重要的是加载可执行文件和动态链接库的加载,加载的步骤可以分为以下几步
- load dylibs 载入动态库,包括引用的第三方和自定义的动态库
- rebase/bind rebase修复指向当前镜像内部的资源指针,而bind指的是镜像外部的资源指针
- Object Set Up 注册Objc类、把category的定义插入方法列表、保证Sector的唯一
- initializers Objc的load()函数、C++的构造函数属性函数、非基本类型的C++静态全局变量的创建
main函数之前耗时查看
iOS10之后可以通过Product->Scheme->Edit Scheme->Environment Variables设置key:DYLD_PRINT_STATISTICS value:1来获取main函数之前的耗时
pre-main优化
由整个过程可以知道要想减少Pre-main的时间,在条件允许情况下要减少库的加载、减少Objc类的创建、减少静态对象全局对象等
main之后
在上述执行完之后,程序调用main函数
从函数的概述中可以知道UIApplicationMain函数有以下功能:
- 创建应用对象 如果参数principalClassName指定为空,使用info.plist中NSPrincipalClass对应的值,如果NSPrincipalClass没有设置,使用UIApplication class,delegate class 使用init初始化
- 设置应用代理
- 开启运行循环,开始处理应用事件
- 读取info.plist 如果info.plist中有指定NSMainNibFile和对应的nib文件名,则加载视图
之后会调用应用的代理在
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions{}
进行UIWindow的初始化和第三方配置等;至此程序完成启动的基本流程;
在main函数之后启动时间查看
使用Instruments的time Profiler