大话iOS之RunLoop

2016-11-19  本文已影响158人  o0阿拉斯加的狗0o

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 默认的状态,空闲时候的状态

来看一下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事件

注意: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运行循环函数
上一篇下一篇

猜你喜欢

热点阅读