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 越多,启动越慢

在性能优化方面上更能人为把控的:loadT2时间

load: 是在加载过程中,ViewController中的Load方法是自动执行在main方法前的,如果加载对象及方法过多,启动也会随之更慢。

所以可以拆分的业务,尽可能拆分处理!

T2时间:能不做数据处理尽可能不做,将耗时任务交由线程处理!

 


 

汇报完毕,我们明天见

 

posted @ 2018-12-11 20:15  幽幽幽瓜  阅读(427)  评论(0编辑  收藏  举报