一、什么是 Runloop ?
1、从字面上讲就是运行循环;
2、它内部就是 do-while 循环,在这个循环内部不断地处理各种任务;
3、一个线程对应一个 RunLoop,主线程的 RunLoop 默认已经启动,子线程的 RunLoop 得手动启动(调用 run 方法);
4、 RunLoop 只能选择一个 Mode启动,如果当前 Mode 中没有任何 Source(Sources0、Sources1)、Timer,那么就直接退出 RunLoop;
5、 基本的作用就是保持程序的持续运行,处理 app 中的各种事件。通过 runloop ,有事运行,没事就休息,可以节省 cpu 资源,提高程序性能。
二、RunLoop 对象
iOS 中有 2 套 API 来访问和使用 RunLoop
1>. Foundation: NSRunLoop
2>. Core Foundation: CFRunLoop
3>. NSRunLoop 和 CFRunLoopRef 都代表着 RunLoop 对象
4>. NSRunLoop 是基于 CFRunLoopRef 的一层OC包装,所以要了解 RunLoop 内部结构,需要多研究 CFRunLoopRef 层面的 API。
三、RunLoop 与线程
1>. 每条线程都有唯一的一个与之对应的 RunLoop 对象。
2>. 主线程的 RunLoop 已经自动创建好了,子线程的 RunLoop 需要主动创建。
3>. RunLoop 在第一次获取时创建,在线程结束时销毁。
四、获得 RunLoop 对象
1>. Foundation
[NSRunLoop currentRunLoop]; // 获取当前线程的 RunLoop 对象
[NSRunLoop mainRunLoop]; // 获得主线程的 RunLoop 对象
2>. Core Foundation
CFRunLoopGetCurrent(); // 获得当前线程的 RunLoop 对象
CFRunLoopGetMain(); // 获得主线程的 RunLoop 对象
五、RunLoop 相关类
Core Foundation 中关于 RunLoop 的5个类
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
1>. CFRunLoopModeRef
**、CFRunLoopModeRef 代表 RunLoop 的运行模式。
**、一个 RunLoop 包含若干个 Mode ,每个Mode 又包含若干个(set)Source/(array)Timer/(array)Observer
**、每次 RunLoop 启动时,只能指定其中一个 Mode ,这个 Mode 被称作 CurrentMode
**、如果需要切换 Mode ,只能退出 Loop ,再重新指定一个 Mode 进入
**、这样做主要是为了分隔开不同组的 Source/Timer/Observer, 让其互不影响
**、mode 主要是用来指定事件在运行循环中的优先级的,分为:
NSDefaultRunLoopMode (kCFRunLoopDefaultMode):默认,空闲状态。
UITrackingRunLoopMode :ScrollView 滑动时会切换到该 Mode
UIInitializationRunLoopMode :run loop 启动时,会切换到该 Mode
NSRunLoopCommonModes (kCFRunLoopCommonModes) :Mode 集合,苹果公开提供的Mode 有两个:
NSDefaultRunLoopMode (kCFRunLoopDefaultMode)
NSRunLoopCommonModes (kCFRunLoopCommonModes)
2>. CFRunLoopTimerRef
CFRunLoopSourceRef 是事件源(输入源)
按照官方文档,Source 的分类
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources
按照函数调用栈, Source 的分类
Source0 :非基于 Port 的
Source1 :基于 Port 的,通过内核和其他线程通信,接收、分发系统事件。
3>. CFRunLoopObserverRef
**、CFRunLoopObserverRef 是观察者,能够监听RunLoop 的状态改变
**、可以监听的时间点有以下几个:
kcfRunLoopEntry (即将进入 loop)// 1
kcfRunLoopBeforeTimers (即将处理 timer)// 2
kcfRunLoopBeforeSources (即将处理 source)// 4
kcfRunLoopBeforeWaiting (即将进入休眠)// 32
kcfRunLoopAfterWaiting (刚从休眠中唤醒)// 64
kcfRunLoopExit (即将退出 loop)// 128
**、添加 Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"---监听到 RunLoop 状态发生改变 --- %zd", activity);
});
// 添加观察者:监听 RunLoop 的状态
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
// 释放 Observer
CFRelease(observer);