美文网首页iOS开发基础
# iOS基础 # App生命周期知识学习整理

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

作者: 就叫yang | 来源:发表于2018-12-04 15:59 被阅读17次

    做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生命周期知识学习整理

        本文链接:https://www.haomeiwen.com/subject/bexvcqtx.html