IOS —— App启动原理及代码优化
哈喽,好久不见。最近处于心情低迷期就没怎么来更新文章了。
在下也算是个半路出家的代码家,从之前的文章更新到现在
依然是还是从基础学起,万物归基础!
所以从今天起每天回来更新汇报学习成果!!每天
今天主要接触的是Application相关的知识,包括App启动原理,以及windos窗口控制以及Appdelegate的模块优化等~
1.App启动原理
在我们创建项目时,有个不起眼的main.m文件,里头只有一个方法,返回的也只有一个int对象。在我刚接触IOS学识时,这一个不起眼的文件经常给我分类放在了一个文件夹里。
具体有什么用并没有深究,但是我只知道的是没回报错都是从main文件里传出来的。
那么main.m文件到底蕴含着什么东西呢?
int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc , argv , nil , NSStringFromClass([Appdelegate clasee])); } }
Main文件中返回了一个UIApplicationMain对象,UIApplicationMain可厉害了
他干了这么几件事情
1.创建了 UIApplication 应用对象
2.创建了Application delegate(AppDelegate) 对象
3.建立了一个Event Loop (创建了Runloop对象并且开启事件循环)
4.读取info.plist文件
5.基于以上对象(UIApplication、AppDelegate、Runloop)创建一个windos
并且他本身就是一个死循环。为什么呢?
这得从事件循环,也就是Runloop对象说起。
苹果的系统夸张的说,就是对Event loop的实现所建立的
当应用启动时 - >开启一个死循环Runloop
当页面静止时 -> Runloop处于wait状态。
当触发事件时 ->判断事件来源(handle_msg),
根据来源处理触发事件
1.定时器
2.GCD
3.Source1
处理结束后,继续进入等待状态或者应用结束退出循环。
简要地说就是这么一个周而复始的过程(具体可以看第一篇关于RunLoop的白话文)
这里可能有人会做一个小小的质疑,你说死循环就死循环?怎么证明给我们看?
也可以
int main(int argc, char * argv[]) { @autoreleasepool { int back = UIApplicationMain(argc , argv , nil , NSStringFromClass([Appdelegate clasee])); NSLog(@"back == %d",back); return back; } }
这里将UIApplicationMain拆分成int对象并且打印他。
因为他是死循环的缘故所以NSLog并不会打印出来(不信你可以试一下)。
讲了那么多关于ApplicationMain的东西,到底和代码优化有什么关系呢?
在说优化之前,还得讲到的一个特殊的东西,UIWindos
众所周知,在IOS的APP中windos通常只有一个,是一种特殊的UIView。
UIWindos有属于自身的层级对象UIWindosLevel,UIWindosLevel的属性有三,对应关系如下
UIWindosLevelAlert > UIWindosLevelStatusBar > UIWindosLevelNormal
虽然话说Windos通常只有一个,但是并不是不可创建的,以上的属性就是对于创建多个windos时,可用于控制层级显示。
windos的作用呢,就是加载视图,就类似app中里面的电视机。少了他App什么都不是。
那么Windos怎么创建呢? 这是application的子类的中的方法
static UIWindow *__xgWindows; @implementation AppDelegate (XGApp) - (void)startLoadAd { __xgWindows = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; __xgWindows.rootViewController = [XgADViewController new]; __xgWindows.windowLevel = UIWindowLevelAlert; [__xgWindows makeKeyAndVisible]; // [self performSelector:@selector(finishWindos) withObject:nil afterDelay:3]; NSLog(@"加载广告页"); }
删除呢?只需要设置监听对象,触发方法将Windos设置为nil即可。
以下是触发方法。
- (void)finishWindos { NSLog(@"关闭Windos"); __xgWindows = nil; }
这里我们可以根据代码分析得知,我们是可以创建application的子类,来进行许多业务的处理。
上述例子我们运用application的子类GgApplication创建了一个广告页,并在三秒销毁了。在主线程的application didFinishLaunchingWithOptions~方法中
只用了一行代码就解决了,一般来说在Application里,因为Delegate的方法是启动的一部分,所以代码过于拥挤的话是会影响可视性以及启动的速度的。
所以在可拆分的情况下,业务尽可能的多的拆分到子类中处理时有助于提高性能的!
在第一个视图中,不相关的数据处理,都可以放到线程中处理(比较耗时的任务)*(省,市)数据加载
需要注意的是,逻辑必须的清晰。因为APPDelegate是启动的一部分,稍有差错是会影响整体运作流畅性的。
如果整体启动过慢,APP开启时间 ≥ 5s 时, 苹果官方甚至会将整个App打回不允许上架。这是需要注意的。
2.代码优化
关于启动时间的优化,这边给出一小部分公式希望能帮助到读者。
启动的时间 = T1 + T2
T1(Main方法执行前) 系统环境布局时间:创建进程、加载分析可执行文件(库加载、堆栈环境配置等)
T2(Main方法执行后):从Main方法执行到第一个界面显示的时间
其中有以下四点是影响启动速度的
1.库加载越多,启动越慢
2.Objc类越多,启动越慢
3.静态对象、全局对象越多、启动越慢
4.Objc的 +load 越多,启动越慢
在性能优化方面上更能人为把控的:load 和T2时间
load: 是在加载过程中,ViewController中的Load方法是自动执行在main方法前的,如果加载对象及方法过多,启动也会随之更慢。
所以可以拆分的业务,尽可能拆分处理!
T2时间:能不做数据处理尽可能不做,将耗时任务交由线程处理!
汇报完毕,我们明天见