这个流程大多数参考文章都已经比较旧, 参考价值不大, 所以直接对照源码解析
我对 runloop 源码的解析:
数据结构源码解析
CFRunloopRun 源码解析
一些其他函数解析所使用的源码版本:
CF-1151.16.tar
本文主要是对 Runloop 执行过程的解读, 对源码的主要分析过程在此: CFRunloopRun 源码解析
函数调用流程

CFRunLoopRun
最外层的函数, 主要是提供给外层的封装
主要是在维护一个循环, 然后调用当前线程, 以默认模式(kCFRunLoopDefaultMode)执行函数 CFRunLoopRunSpecific
CFRunLoopRunSpecific
这是个通用 runloop 执行函数, 依赖传入的线程,传入的模式, 超时等
其主要职责是负责Mode 过滤及切换
对于空 Mode, 在这一步被过滤, 不会真正执行
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
Boolean did = false;
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
由于有效 mode, 缓存起上一次的 Mode, 发送通知, 并执行 __CFRunLoopRun
✨₁ 此处调用了 Observer (之后会做归纳)
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopRun
源码解析见 CFRunloopRun 源码解析
其流程如下:

图中 “问号” 部分为看源码不确定的内容, 其中 source1 和休眠都涉及到 mach( 其他: Mach 是什么 )
对应的步骤中,会调用数据结构中提到的函数 二. runloop 的数据结构
解析写在 其他: 一些其他函数解析(CFRunLoopDoObservers、__CFRunLoopDoBlocks、__CFRunLoopDoSources0)
- 调用 Observer:
__CFRunLoopDoObservers - 执行 Sources0:
__CFRunLoopDoSources0 - 处理 Timer:
__CFRunLoopDoTimers - 处理 Blocks:
__CFRunLoopDoBlocks
流程:
- loop 状态判断: 查是否已经结束, 如果结束,直接走 return
- 设置超时: 根据入参, 设置对应的超时
- 初始化循环条件 & 进入循环
- 调用 Observer: (✨₃)
kCFRunLoopBeforeTimers(其实离执行还有段时间,Timers 在 source 0 之后) - 调用 Observer: (✨₄)
kCFRunLoopBeforeSources - 处理 Blocks: 我们
dispatch_asyn,dispatch_sync的内容, 就是到了 blocks 中 - 执行 Sources 0: 执行 source 0
- 处理 Blocks: 我推测是执行 source0 的过程中可能导致新的 blocks 被加入, 所以又执行了一次(后面还有几次类似的操作)
- 判断 Source 1: 这两块代码被一些宏控制, 我没找到宏定义. 但是如果不是这就没地方执行 source 1, 内部是 match 的调用
- 处理 Sources 1: 这块根据判断, 如果有 source1, 就不会进入休眠, 而是直接跳到16
- 调用 Observer: (✨₅)
kCFRunLoopBeforeWaiting - 准备休眠: 代码中设置了一些休眠状态
- 开始休眠: 源码其实没找到正在的休眠逻辑, 猜测是
__CFRunLoopServiceMachPort内部带了 - 休眠结束:
- 调用 Observer: (✨₆)
kCFRunLoopAfterWaiting - 处理 Timer: 一个很大的 if-else, 根据宏判断最后会执行到
__CFRunLoopDoTimers - 处理 Blocks: 同上blocks, 应该是因为 Timer 中可能包含 block, 所以又执行一次
- 决定执行结果, 重新循环,或者结束
Runloop 休眠
❓这块我没看明白源码,调用的是__CFRunLoopServiceMachPort
根据其他参考文章,其内部的 mach_msg 是切换到 “内核态”:
- 没有消息时, 保持休眠
- 有消息时, 唤醒线程
Observer 所有被触发的时机
(✨ 表示文章的定位位置)
kCFRunLoopEntry: (✨₁) 执行真正的 loop 前(__CFRunLoopRun)kCFRunLoopBeforeTimers: (✨₃) 开始 Timer 前(其实 source 更早)kCFRunLoopBeforeSources:(✨₄) 开始 Source 0 前kCFRunLoopBeforeWaiting:(✨₅) 开始 休眠 前kCFRunLoopAfterWaiting: (✨₆) 结束休眠kCFRunLoopExit: (✨₂) loop 执行完毕
#猿人/猿艺/iOS/基石/runloop/正文