7-3.【OC】【RunLoop】RunLoop 的三大入口 / 三大组件是什么?并说明各自职责。

2 阅读2分钟

从底层的 CFRunLoop.c 源码结构来看,RunLoop 的运行完全依赖于它的三个核心组件。通常我们称之为 SourceTimerObserver

这三个组件被统称为 Mode Item,因为它们必须被加入到某个特定的 Mode 中才能生效。


1. Source (事件源)

Source 是 RunLoop 的“体力劳动者”,负责接收并处理各种外部事件。它又细分为两类:

  • Source0 (非系统内核管理)

    • 职责:处理 App 内部事件。它并不能主动唤醒 RunLoop。
    • 特点:你需要先调用 CFRunLoopSourceSignal(source) 将其标记为待处理,然后手动调用 CFRunLoopWakeUp 唤醒 RunLoop,它才会执行。
    • 常见例子:触摸事件处理、performSelector:onThread:
  • Source1 (基于 Mach Port / 系统内核管理)

    • 职责:处理来自系统内核或其他进程的消息。
    • 特点具备主动唤醒 RunLoop 的能力。当 Mach Port 收到消息时,内核会自动唤醒处于休眠状态的线程。
    • 常见例子:硬件交互(如点击屏幕后的底层电信号转分发)、进程间通信(IPC)。

2. Timer (定时器)

Timer 是 RunLoop 的“闹钟”,负责在预设的时间点唤醒线程执行任务。

  • 职责:基于时间的特定回调。它实际上也是一种特殊的 Source(在底层被封装为 CFRunLoopTimerRef)。

  • 特点

    • 受 Mode 影响:正如我们之前聊过的,如果 Timer 所在的 Mode 不是当前运行的 Mode,定时器就不会触发。
    • 非高精度:如果 RunLoop 正在执行一个耗时的 Source0 任务,Timer 的回调会被推迟(Tolerance)。
  • 常见例子NSTimerperformSelector:withObject:afterDelay:


3. Observer (观察者)

Observer 是 RunLoop 的“监视器”,它并不处理具体的业务逻辑,而是负责监控 RunLoop 本身的运行状态。

  • 职责:在 RunLoop 运行的各个关键节点(时间点)触发回调,让我们可以介入做一些额外工作。

  • 特点:可以监听以下状态:

    1. kCFRunLoopEntry:即将进入 RunLoop。
    2. kCFRunLoopBeforeTimers:即将处理 Timer。
    3. kCFRunLoopBeforeSources:即将处理 Source。
    4. kCFRunLoopBeforeWaiting即将进入休眠(这是处理界面刷新的黄金时机)。
    5. kCFRunLoopAfterWaiting:刚从休眠中唤醒。
    6. kCFRunLoopExit:即将退出。
  • 常见例子AutoreleasePool 的创建与销毁、UI 界面的布局刷新(Layout Subviews)、卡顿监控。


总结:三者的协同工作

我们可以把 RunLoop 比作一个待命的士兵

  1. Source 是他的长官,下达具体的战斗指令(点击、网络请求)。
  2. Timer 是他的闹钟,提醒他什么时候该巡逻(定时任务)。
  3. Observer 是他的随从,记录他什么时候睡觉、什么时候起床,并在他睡觉前提醒他把地扫了(释放内存池、刷新 UI)。
组件核心职能是否能唤醒 RunLoop
Source0内部事件(如点击处理)
Source1内核/系统消息
Timer延迟/定时任务
Observer状态监控