源码来源: https://opensource.apple.com/tarballs/CF/
使用的源码版本: CF-1151.16.tar
部分解释和源码中看不懂的含义参考自:
深入理解RunLoop | Garan no dou(15 年的老文章了,代码较旧)
下面内容只涉及核心字段, 目的是了解 runloop 数据结构及各结构体之间的关系以及其整体设计思路
剩余的很多字段是在 runloop 执行时, 用于记录某些变量用的, 暂时不细究
一.runloop 是什么 从这里我们知道, runloop 有四个基本概念 Thread, Runloop,Mode,Item
其中后面三个概念属于 Runloop,
数据结构关系是:
Thread与Runloop一对一- 一个
Runloop包含多个Mode, 一个Mode中包含多个 Item Item分为三种Source,Timer,ObserverSource又分为两种:Source0,Source1
除了 Thread 是用的 pthread_t 外整体关系如下图所示:

从右到左讲起
CFRunLoopSourceRef & __CFRunLoopSource
CFRunLoopSourceRef , 接口中常见的类型, 本质是 __CFRunLoopSource 的指针类型
__CFRunLoopSource的核心属性:
CFMutableBagRef: 所属的 runloop- union 是联合体, 理解为下面描述的所有字段都在同一块内存地址, 并且同时只能是其中一个
version0: 上面提到的 source 0: 需要手动触发唤醒的事件,version1: 上面提到的 source 1: 由内核触发事件, 基于端口的线程通信, 能主动唤醒 Runloop
具体source 0和source 1见正文部分 一.数据结构
// 省略一部分字段
struct __CFRunLoopSource {
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
CFRunLoopTimerRef & __CFRunLoopTimer
CFRunLoopObserverRef, 接口中常见的类型, 本质是 __CFRunLoopTimer 的指针类型
__CFRunLoopTimer 核心部分:
runloop: 所属 RunlooprlModes: 所属的 modenextFireDate: 下一次触发时间interval: 触发间隔tolerance: 时间宽容度(误差?)_fireTSR: 根据runloopRun函数来看,应该是触发的时间_callout: 触发时执行的事件回调
从其中的从属关系来看, Timer 不像其他 Item(Source, Observer)他不是隶属于某个的 Modes 的
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
struct __CFRunLoopTimer {
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval; /* immutable */
CFTimeInterval _tolerance; /* mutable */
uint64_t _fireTSR; /* TSR units */
CFRunLoopTimerCallBack _callout; /* immutable */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
CFRunLoopObserverRef & __CFRunLoopObserver
CFRunLoopObserverRef, 接口中常见的类型, 本质是 __CFRunLoopObserver的指针类型
typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoopObserver * CFRunLoopObserverRef;
__CFRunLoopObserver 的核心属性:
runloop: 所属的 runloop_activities: runloop 的活动状态, 本质是个整型_callout: 回调函数, 本质是个函数指针_context: 上下文, 存放了一些 observer 的描述信息
typedef unsigned long long CFOptionFlags;
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
// 省略了一部分字段
struct __CFRunLoopObserver {
CFRunLoopRef _runLoop;
CFOptionFlags _activities; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
CFRunLoopObserverContext: Observer 信息
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopObserverContext;
CFRunLoopRef & __CFRunLoop
CFRunLoopRef 也是我们在接口中常见的类型, 本质是__CFRunLoop的指针类型
typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;
__CFRunLoop的核心属性:
- _modes: runloop 所拥有的所有 mode
- _currentMode: runloop 中当前的 mod
- _commonModes: runloop 中被标记为 Common 的 modes
- _commonModeItems: runloop 中被标记为 Common 的 items(Observer, Timer, Source)
runloop 执行时, 有一部分的 mode 或者 item 可以手动加入 Common 中, 起到这么一个作用:
所有加入了 _commonModeItems 中的内容, 会在执行时被自动同步到加入 _commonModes 的 Mode 中
// 省略了一部分字段
struct __CFRunLoop {
CFMutableSetRef _modes;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
};
CFRunLoopModeRef & __CFRunLoopMode
CFRunLoopModeRef 是比较常见的类型, 本质就是__CFRunLoopMode 的指针类型
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
先看 __CFRunLoopMode 的核心属性:
- mode 名字
- _pthread: 对应的线程;
- source0: 上面 [
__CFRunLoopSource]https://mjxin.github.io/2020/07/02/OC%E5%9F%BA%E7%9F%B3-Runloop-%E9%99%84%E5%BD%95-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90.html#cfrunloopsourceref–__cfrunloopsource),Source 0 的集合 - source1: 上面
__CFRunLoopSource,Source 1 的集合 - observers: 上面
__CFRunLoopObserver, observer 的集合 - timers: 上面
__CFRunLoopTimer, Timer 的集合 - _blocks_head: 存储被
dispatch_sync,dispatch_async到当前 runloop 中的 block(头结点) - _blocks_tail: 存储被
dispatch_sync,dispatch_async到当前 runloop 中的 block(尾结点) - 上面这两很明显是个链表
// 省略了一部分字段 struct __CFRunLoopMode { CFStringRef _name; CFMutableSetRef _sources0; CFMutableSetRef _sources1; CFMutableArrayRef _observers; CFMutableArrayRef _timers; struct _block_item *_blocks_head; struct _block_item *_blocks_tail; }; -
不属于 Runloop 三元素但被用到的数据结构
_block_item: 就是我们 dispatch 进来的block可以看到我们的
block被封装为了链表结构- _next: 下一个节点
- _mode: block 所在的模式
- _block: block 的函数体
struct _block_item { struct _block_item *_next; CFTypeRef _mode; // CFString or CFSet void (^_block)(void); };
#猿人/猿艺/iOS/基石/runloop/正文