启动过程
一. 加载main函数,应用创建的第一个实例就是main函数中的UIApplicationMain实例
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, @"EOCApplication", NSStringFromClass([EOCAppDelegate class]));
}
}
前两个参数:argc是命令行总的参数个数,argv是参数的数组,值得一提的是argv中第一个参数为app的路径+全名。
默认的第三个参数是nil,但是它实际传的是UIApplication,我们也可以写一个继承自UIApplication的类* EOCApplication来代替它。
NSStringFromClass方法是为了更安全,确保它是一个字符串类型,里面的类默认的是AppDelegate,但是我们也可以写一个继承自UIResponder的类来代替,如果没有响应事件,也可以只是继承自NSObject。但是都必须遵循UIApplicationDelegate*代理方法,并且在.h文件中声明一个window属性,因为只有声明了window属性,控制器才能够加载window。
@interface EOCAppDelegate : NSObject
@property (strong, nonatomic) UIWindow *window;
@end
声明window属性,必须头文件要引入UIKit框架
二. 在main函数中创建Application对象 创建Application的Delegate对象。
三. 开启主事件循环runloop,AppDelegate代理对象开始监听系统事件(这是一个死循环,APP就是在这个循环里面监听并处理事件)。
四. 启动完毕会调用 didFinishLaunching方法,并在这个方法中创建并显示UIWindow
- 设置UIWindow的根控制器是谁
- 如果有storyboard,会根据info.plist中找到应用程序的入口storyboard并加载箭头所指的控制器
- 显示窗口
runloop
runloop源码地址:地址
内部原理大概如下:
runloop while (1){
model while(1){
切换的时候
跳出去了
}
}
隐藏状态栏
其中根视图最好固定,需要到登陆界面就跳转过去 在keyWindow上进行操作
windowLevel
UIWindowLevelAlert > UIWindowLevelStatusBar > UIWindowLevelNormal
其中隐藏状态栏,可以在didFinishLaunchingWithOptions方法中将keyWindow的层级设置为最高,因为状态栏其实也是一个window,这样就会覆盖掉状态栏,但是这样在整个APP里面都覆盖了
self.window.windowLevel = UIWindowLevelAlert;
当然也还有其他的方法隐藏状态栏
关于AppDelegate中的一些调用顺序
应用从前台进入后台
- applicationWillResignActive
- applicationDidEnterBackground
先失去焦点,再进入后台
从后台进入前台
- applicationWillEnterForeground
- applicationWillResignActive
先进入前台,再获取焦点。但是如果在进入前台的时候,你进行了大量的操作,比如说请求数据之类的,可能会引起卡顿,所以这个时候,可以另外开辟一个线程来做这些操作
关于项目拆分
可以使用分类或者类工厂来进行拆分
分类
为了使AppDelegate代理方法中的代码,更加方便阅读,可以按照业务创建几个AppDelegate的分类,然后再在主要的AppDelegate中进行调用。
类工厂
关于项目添加文件夹的时候
group :一般只在你的工程中是文件夹的形式,但是在本地的目录中还是以散乱的形式放在一起的,除非你是从外部以group的形式引用进来的。
folder: 只能作为资源,整个引用进项目,不能编译代码,也就是说,以folder形式引用进来的文件,不能被放在complie sources列表里面
启动时间
时间分为两个部分 T1(main前) + T2(main后), {T1:系统环境布局时间:创建进程,加载解析可执行文件(库加载,堆栈环境配置等等), T2:从main到第一个界面显示时间}
1、 库加载越多,启动越慢
2、 Objc类越多,越慢
3、 静态对象全局对象越多,启动越慢
4、 Objc的 +load越多,启动越慢
更能把控的:load 和 T2时间上进行优化 (前面三点随着项目越大,库和类就越多,我们不太好进行优化)
每个控制器的load加载在main函数运行之前,并且按照项目中文件配置先后顺序加载:
我们尽可能少用控制器的load方法,已经在里面少做耗时的操作,如果有一些操作,可以用initialize方法代替
T2时间即是:从didFinishLaunchingWithOptions这个方法到显示出第一个界面的时间。所以我们尽可能在这个方法中少做操作,如果有耗时的操作移到子线程,也就是第一个界面出来之后再执行,可以做到优化
参考文章:
iOS 从main函数开始
iOS:App启动过程详解
iOS APP启动时所有方法的调用顺序分析