1. 概念
RunLoop
是通过内部维护的事件循环
来对事件/消息进行管理
的一个对象
.
事件循环
- 没有消息需要处理时, 休眠以避免资源占用 (
用户态
=>内核态
) - 有消息需要处理时, 立即被唤醒 (
内核态
=>用户态
)
1 | int main() { |
2. 数据结构
NSRunLoop
是CFRunLoop
的封装, 提供了面向对象的API.NSRunLoop
(NSFoundation
),CFRunLoop
(CoreFoundation
)CFRunLoop
;CFRunLoopMode
;Source/Timer/Observer
CFRunLoop
1 | pthread // --对应(RunLoop和线程关系) |
CFRunLoopMode
1 | name // NSDefaultRunLoopMode |
CFRunLoopSource
1 | // 需要手动唤醒线程 |
CFRunLoopTimer
1 | // 基于事件的定时器, 和NSTimer是toll-free bridged的,可以混用. |
CFRunLoopObserver
1 | // 表示观察者, 每个Observer 都包含了一个回调(函数指针),当RunLoop的状态发生变化时, 观察者就能通过回调接受到这个变化 |
对应关系
(1)RunLoop -> (n)Mode ->(m)[Source/Timer/Observer]
RunLoop的Mode
1 | // 默认情况下RunLoop仅能处理运行在当前Mode的事件/消息, |
CommonMode的特殊性
- 以
NSRunLoopCommonModes
表示 CommonModes
不是实际存在的Mode
- 是同步
Source/Timer/Observer
到多个Mode
中的一种技术解决方案
3. 事件循环机制
void CFRunLoopRun()
大致流程
- 即将进入RunLoop // 通知Observer (见
CFRunLoopObserver
观测时间点时机)
- 即将进入RunLoop // 通知Observer (见
- 将要处理Timer/Source0事件 // 通知Observer
- 处理Source0事件
- 如果有Source1事件要处理, 直接到
(8.)
, 否则(5.)
- 如果有Source1事件要处理, 直接到
- 线程将要休眠 // 通知Observer
- 休眠, 等待唤醒 => (被唤醒条件 1. source1; 2.timer事件回调; 3.外部收到唤醒)
- 线程刚被唤醒 // 通知Observer
- 处理唤醒时收到的消息 // 处理完, 回到
(2.)
- 处理唤醒时收到的消息 // 处理完, 回到
4. RunLoop与NSTimer
void CFRunLoopAddTimer(runLoop, timer, commonMode)
5. RunLoop与多线程
线程与RunLoop一一对应.
自己创建的线程默认是没有RunLoop的.
实现常驻线程
- 为当前线程开启一个RunLoop.
- 向该RunLoop中添加一个Port/Source等维护RunLoop的事件循环.
- 启动该RunLoop.
1 | static NSThread *thread = nil; |
总结
什么是RunLoop, 怎么做到有事做事,没事休息?
1 | 1. RunLoop通过内部维护的事件循环来对事件/消息进行管理的一个对象. |
RunLoop与线程的关系
1 | 1. 一一对应 |
实现常驻线程
见前文(5)
怎么保证子线程数据返回更新UI的时候不打断用户的滑动操作?
1 | 把子线程返回的数据进行主线程UI更新逻辑包装, 放到到主线程kCFRunLoopDefaultMode上提交, |
参考文章
- 本文作者: 醉疏狂
- 本文链接: https://hubin97.github.io/2020/05/20/RunLoop/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!