美文网首页
大话iOS之RunLoop

大话iOS之RunLoop

作者: o0阿拉斯加的狗0o | 来源:发表于2016-11-19 18:37 被阅读158次

    iOS系统中有两个关于Runloop的对象:NSRunLoop 和 CFRunLoopRef
    NSRunloop是Foundation框架提供的,是对CoreFoundation框架提供的CFRunloopRef的封装。
    CoreFoundation提供的是纯C语言的API,都是线程安全的,Foundation不是线程安全的。
    iOS中RunLoop是开源的,在CoreFoundation的开源代码中,可以在这里下载:RunLoop源码

    CFRunLoopMode

    RunLoop在同一时段内只能并且必须在一种特定的Mode下run,这个Mode被称为currentMode
    如果想更换当前的mode,需要暂停当前的loop,然后重启新的loop,这样可以分离开不同的Source/Timer/Observer,互不影响
    可以定义自己的mode,但是几乎没有这么做的

    • NSDefaultRunLoopMode 默认的状态,空闲时候的状态
    • UITrackingRunLoopMode 滑动跟踪,滑动scrollView的时候处于这个状态,保证界面滑动时不受其他界面的影响
    • UIInitializationRunLoopMode 私有的mode,App启动的时候的状态,加载出第一个页面后,就转成了Default
    • NSRunLoopCommonModes 默认的是包括DefaultTracking两个状态,也可以自定义的往里面添加
    • GSEventReceiveRunLoopMode接受系统事件的内部 Mode,通常用不到

    来看一下CFRunLoopMode的构成

    RunLoopMode的结构.png RunLoop源码中的mode的定义.png

    可以看到,一个Runloop可以包含如果个Mode,每个Mode又包含了多个Source/Timer/Observer

    CFRunLoopSource

    CFRunLoopSource是RunLoop的数据源抽象类,类似Objective-C中的协议protocol,实现了这个protocol就可以充当RunLoop的数据源(几乎没有这么做的),RunLoop自己定义了两个Source:Source0和Source1

    • Source0 : 处理App内部事件,比如屏幕响应UIEvent, CFSocket,我们点击屏幕就是Source0事件
    • Source1 : 由内核管理,比如mach_port

    注意:mach_port是iOS系统中进程间通信的一种方式,如果进程1往一个port中发送一个消息,此时进程2监听了这个port,就会拿到这个消息
    NSPort是对CoreFoundation中的CFMachPort和CFMessagePort的封装
    来看一下对source事件的定义

    RunLoop中对于source事件的定义.png
    CFRunLoopSource中用union确保这个source要么是source0,要么是source1
    看一下source0和source1的具体定义: source0的定义 source1的定义.png

    souce0中定义的都是函数指针
    source1中出了函数指针,还有一个mach_port

    CFRunLoopObserver

    CFRunLoopObserver相当于观察者模式的观察者,用来向观察者报告RunLoop当前的状态

    下面是RunLoop中定义的状态:

    RunLoop所有的状态.png
    我们可以用下面的代码创建一个CFRunLoopObserver,添加到当前线程的RunLoop中,监听当前线程Runloop的当前状态
    例如应用启动的时候,会处理一系列的source事件和timer事件,当处理完之后,就会打印出即将进入 休眠,此时,我们点击屏幕,会打印出刚从休眠中唤醒,然后再处理一系列的source和timer事件,然后再次进入休眠状态。
    CFRunLoopObserverRef observe = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            switch (activity) {
                case kCFRunLoopEntry:
                    NSLog(@"即将进入 loop");
                    break;
                case kCFRunLoopBeforeTimers:
                    NSLog(@"即将处理 timer");
                    break;
                case kCFRunLoopBeforeSources:
                    NSLog(@"即将处理 source");
                    break;
                case kCFRunLoopBeforeWaiting:
                    NSLog(@"即将进入 休眠");
                    break;
                case kCFRunLoopAfterWaiting:
                    NSLog(@"刚从休眠中唤醒");
                    break;
                case kCFRunLoopExit:
                    NSLog(@"即将退出 loop");
                    break;
    
                default:
                    break;
            }
        });
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), observe, kCFRunLoopDefaultMode);
    
        CFRelease(observe);
    

    CFRunLoopObserver 与 AutoreleasePool

    AutoreleasePool在RunLoop的两次sleep之间对AutoreleasePool进行pop和push,将这次loop中产生的Autorelease对象进行释放

    RunLoop的运行机制

    关于运行机制,先来看两幅图:

    官方文档中的RunLoop的运行图.png 更容易理解的RunLoop的运行图.png

    上面的两张图的运行循环的逻辑,都对应着源码中的__CFRunLoopRun这个函数


    RunLoop运行循环函数

    相关文章

      网友评论

          本文标题:大话iOS之RunLoop

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