# iOS基础 # App生命周期知识学习整理

做iOS开发日常不怎么涉及到这些内容,但总会遇见相关的bug或者一些优化需求。下面整理学习一些知识。

程序启动过程发生了什么?

启动后发生了什么?

程序启动后的生命周期是怎么样的?

如何优化启动时间?

App启动过程

iOS开发中,main函数是我们熟知的程序启动入口,但实际上并非真正意义上的入口,因为在我们运行程序,再到main方法被调用之间,程序已经做了许许多多的事情,比如我们熟知的runtime的初始化就发生在main函数调用前,还有程序动态库的加载链接也发生在这阶段。

1、系统先读取App的可执行文件(Mach-O文件),获取到dyld的路径,并加载dyld(动态库链接程序)。

2、dyld去初始化运行环境、开启缓存策略、加载依赖库、我们的可执行文件、链接依赖库,并调用每个依赖库的初始化方法。

3、在上一步runtime被初始化,当所有的依赖库初始化后,程序可执行文件进行初始化,这个时候runtime会对项目中的所有类进行类结构初始化,然后调用所有类的+load方法。

1、runtime初始化方法 _objc_init 中最后注册了两个通知:

map_images: 主要是在镜像加载进内容后对其二进制内容进行解析,初始化里面的类结构等

load_images: 主要是调用call_load_methods 按照继承层次依次调用Class的 +load方法 然后是Category的+ load方法。(call_load_methods 调用load 是通过方法地址直接调用的load方法,并不是通过消息机制,这就是为什么分类中的load方法并不会覆盖主类以及其他同主类的分类里的load 方法实现了。)

2、runtime 调用项目中所有的load方法时,所有的类的结构已经初始化了,此时在load方法中可以使用任何类创建实例并给他们发送消息。

4、最后dyld返回main函数地址,main函数被调用。

App启动后

App启动后执行流程

main() -> UIApplicationMain() -> UIApplication 构建、Appdelegate 构建、info.plist文件加载

UIApplication -> runloop创建

Appdelegate(代理)  -> didFinishLaunchingWithOptions 函数执行( window构建、RootVC构建)

app运行的五种状态

ios app有5种状态,分别是:

1、Not running未运行:app没启动或被迫终止。

2、Inactive未激活:当前应用正在前台运行,但是并不接收事件(当前或许正在执行其它代码)。一般每当应用要从一个状态切换到另一个不同的状态时,中途过渡会短暂停留在此状态。唯一在此状态停留时间比较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(诸如电话来电、有未读短信等)事件的时候。

3、Active激活:当前应用正在前台运行,并且接收事件。这是应用正在前台运行时所处的正常状态。

4、Backgroud后台:程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会。时间到之后会进入挂起状态(Suspended)。经过特殊的请求后可以长期处于Backgroud状态。

5、Suspended挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。

App的生命周期

application:didFinishLaunchingWithOptions:   这是程序启动时调用的函数。

applicationDidBecomeActive:  应用在准备进入前台运行时执行的函数。

applicationWillResignActive:   应用当前正要从前台运行状态离开时执行的函数。

applicationDidEnterBackground: 此时应用处在background状态,并且没有执行任何代码,未来将被挂起进入suspended状态。

applicationWillEnterForeground:  当前应用正从后台移入前台运行状态,但是当前还没有到Active状态时执行的函数。

applicationWillTerminate:  当前应用即将被终止,在终止前调用的函数。如果应用当前处在suspended,此方法不会被调用。

启动时间优化

启动时间

启动时间是用户点击App图标,到第一个界面展示的时间

启动时间在小于400ms是最佳的,因为从点击图标到显示Launch Screen,到Launch Screen消失这段时间是400ms。启动时间不可以大于20s,否则会被系统杀掉。

在Xcode中,可以通过设置环境变量来查看App的启动时间,DYLD_PRINT_STATISTICS和DYLD_PRINT_STATISTICS_DETAILS。

Edit Scheme - Arguments - Environment Variables

冷启动 和 热启动

如果你刚刚启动过App,这时候App的启动所需要的数据仍然在缓存中,再次启动的时候称为热启动。如果设备刚刚重启,然后启动App,这时候称为冷启动。

优化启动时间

用Time Profiler 检查一遍自己的App。

main函数之前的优化苹果本身已经处理了很好,一般而言,不再需要我们去调整,调整性价比也会比我们调整自己的代码低很多,所以优化启动时间大部分是优化我们自己写的代码。

优化main函数之前的操作

动态库加载优化

加载系统的动态库使很快的,因为可以缓存,而加载内嵌的动态库速度较慢。

所以,提高这一步的效率的关键是:减少我们自己的动态库的数量。

之前公司进行项目模块化的时候拆出来很多库,pod一加载 30几个pod,编译都慢成狗,这种情况建议合并动态库,比如公司内部由私有Pod建立了如下动态库:XXTableView, XXHUD, XXLabel,强烈建议合并成一个XXUIKit来提高加载速度。

runtime初始化优化

合并Category和功能类似的类

删除废弃代码

其他


+load 中少做swizzle 等操作

不要在 Initializers 创建线程等操作

多用swift 静态分发

优化我们自己的代码

从main函数开始执行,到你的第一个界面显示,这期间一般会做的事情:

1、执行AppDelegate的代理方法,主要是didFinishLaunchingWithOptions

2、初始化Window,初始化基础的ViewController结构(一般是UINavigationController+UITabViewController)

3、获取数据(Local DB/Network),展示给用户。

处理方向:

AppDelegate 中的方法

didFinishLaunchingWithOptions 方法


applicationDidBecomeActive 方法


能延迟初始化的尽量延迟初始化,不能延迟初始化的尽量放到后台初始化。

第一个页面展示

延迟初始化那些不必要的 UIViewController

以上两个地方不使用大量占用主线程资源的操作,数据获取解析等放在异步处理。

你可能感兴趣的:(# iOS基础 # App生命周期知识学习整理)