概述
我们一般说的 APP 的启动是从
main
函数开始的,但在main
函数执行前,程序已经执行了许多事情
main 函数执行前
程序会做一系列的初始化工作,动态加载依赖库
- 首先当程序启动时,系统会读取程序的可执行文件(mach-o), 从里面获取
动态加载器
(dylb
)的路径;- 加载
dylb
,dylb
会初始化运行环境,配合ImageLoader
将二进制文件加载到内存中去;- 动态链接依赖库, 初始化依赖库,初始化
runtime
;runtime
会对项目中的所有类进行类结构初始化,调用所有的load
方法;- 最后
dylb
会返回main
函数地址,main
函数被调用,进入程序入口
main 函数执行后
main
函数代码分析 :
int main(int argc, char * argv[])
{
@autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
UIKIT_EXTERN int UIApplicationMain(
int argc,
char * _Nonnull * _Null_unspecified argv,
NSString * _Nullable principalClassName,
NSString * _Nullable delegateClassName
);
UIApplicationMain
函数有四个参数
int argc
: 表示参数的个数char * _Nonnull * _Null_unspecified argv
: 表示装载函数的数组NSString * _Nullable principalClassName
: 表示UIApplication
类名或子类,若为 nil,则默认使用UIApplication
类名NSString * _Nullable delegateClassName
: 表示协议UIApplicationDelegate
的实例化对象名,这个类就是我们熟悉的AppDelegate
main
函数执行顺序
- 内部会调用
UIApplicationMain
函数,创建一个UIApplication
对象和它的代理,就是我们项目中的Appdelegate
类- 开启一个
事件循环
(main runloop), 监听系统事件- 程序启动完毕时,通知代理
Appdelegate
, 调用didFinishLaunching
代理方法,在这里会创建UIWindow
,设置它的rootViewController
,- 最后调用
self.window makeKeyAndVisable
显示窗口
启动时间优化
上面简单描述了程序启动的整个过程,分为 main
函数执行前和执行后,所以优化启动时间也可从两个方面着手
1. main 函数前的时间优化
- 合并功能类似的类和扩展,由于
分类
和oc
的动态绑定有很大关系,所以要尽量减少多余的分类- 移除不需要的动态库,减少动态库的数量,因为链接动态库是需要时间的,在自己
pod
工具库的时候,工具库最好是能合并到一个里面,不要弄太多的类。
2. main 函数后的时间优化
- 这和我们的代码逻辑书写有很大关系,它的执行顺序为 main -> didFinishLanuching -> window、rootViewController -> 获取数据 -> 显示页面
- 这个优化的
核心
就是,少在Appdelegate
中写太多代码,一些耗时的操作尽量不要再这里操作,能延迟初始化的,就延迟,不能延迟的就放到后台- 页面布局逻辑:先显示界面,给一个默认状态视图,等数据请求完毕后再刷新界面,这样比等数据请求完整财显示界面看起来更加时间快。