美文网首页iOS开发程序员
ios内存管理(五):RunLoop与AutoreleasePo

ios内存管理(五):RunLoop与AutoreleasePo

作者: 智小融 | 来源:发表于2018-03-17 18:30 被阅读62次

      RunLoop在ios开发中,是一个非常基础又非常核心的概念,但是由于比较偏底层,所以不是特别容易理解。不过好在其代码是开源的(CFRunLoopRef的源代码在Apple Open Source里面可以找到,类似其他情况NSRunloop是CFRunLoopRef的面向对象封装),相关的文章又非常多,只要多花点时间总能理解清楚。本文接上文,主要从其和AutorelasePool的关系出发,粗略写一下我对Runloop的理解,不会深入写Runloop的细节。

      Runloop到底是什么?首先,ios是一个事件驱动的操作系统,简单来看整个生命周期就是初始化、接收消息,处理消息,整个系统由许许多多个消息处理单元组成;其次,cocoa框架是一个面向对象的框架,面向对象非常重要的一个思想就是对一个过程的封装。所以Runloop其实就是对一个基础事件驱动功能的面向对象封装。它管理了响应的事件类型、响应的过程,处理方式,给外界提供了查询其状态的方法,以及状态改变时告知外界。
      好吧,略去所有细节,Runloop就是一个死循环!当执行run方法后,循环启动,有事件过来就进行处理,否则就休眠(以非常低的资源消耗维持这个死状态)。

      那么,一个应用也就是一个进程,可以有几个Runloop?谁来启动,谁来销毁Runloop呢?
      尝试创建一个NSRunloop对象,看看它的结构:

    NSRunLoop *runloop = [[NSRunLoop alloc] init];
    [runloop run];
    

      打断点观察runloop的结构发现其为nil。这说明我们不能创建NSRunloop对象。查看NSRunLoop.h文件(Foundation框架中),可以看到有两个属性来供框架使用者获取RunLoop对象:

    @property (class, readonly, strong) NSRunLoop *currentRunLoop;
    @property (class, readonly, strong) NSRunLoop *mainRunLoop; // 略去API_AVAILABLE
    

      因为NSRunLoop是对CFRunLoopRef的封装,我们可以在开源代码中查到这两个C函数:CFRunLoopGetMain() 和 CFRunLoopGetCurrent(),对应于这两个属性的getter方法:

    CFRunLoopRef CFRunLoopGetMain() {
        return _CFRunLoopGet(pthread_main_thread_np());
    }
    
    CFRunLoopRef CFRunLoopGetCurrent() {
        return _CFRunLoopGet(pthread_self());
    }
    

      可以看到是通过_CFRunLoopGet这个C函数获取到的。输入的参数不出所料,mainRunLoop是主线程,currentRunLoop是当前线程。这说明RunLoop跟线程是息息相关的。实际上看_CFRunLoopGet函数的源代码就会发现(这里不贴了),RunLoop和线程是一一对应的。必须先有线程,在使用该线程的RunLoop的第一次才完成其初始化,线程销毁时,RunLoop也随之销毁。
      所以我觉得,在ios里,RunLoop是一个依附于线程的、为线程提供持续接收并处理某些类型消息的能力的一个对象。否则没有RunLoop的话,线程执行完毕后既会退出,无法驻留在后台。

      回到RunLoop与AutoreleasePool的关系,上节说了AutoreleasePool的机制,但没有说明具体的创建时机已经drain方法的调用时机,本节就可以给出答案了。RunLoop可以将自己的状态变化告知外界,具体是通过观察者模式实现的,状态变化后,观察者会收到通知,执行相应的代码。
      在程序运行时打断点,可以通过po [NSRunLoop mainRunLoop]查看mainRunLoop的观察者,搜索autorelease可以找到相关的信息。App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。

    相关文章

      网友评论

        本文标题:ios内存管理(五):RunLoop与AutoreleasePo

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