Day8-RunLoop 构成与线程保活
一、RunLoop 的构成
RunLoop 是基于 CFRunLoopRef
(Core Foundation 层)构建的,NSRunLoop
是其 Foundation 层的封装。核心组成如下:
1. RunLoop 对象
- 每条线程都有唯一的一个 RunLoop 对象(主线程默认创建,子线程需手动创建)。
2. RunLoopMode
- RunLoop 在任一时刻只能运行在一种模式下。
- 常见模式:
NSDefaultRunLoopMode
UITrackingRunLoopMode
NSRunLoopCommonModes
3. Source(事件源)
- Source0:非基于 Port 的,如
performSelector:onThread:
- Source1:基于 Port 的,如 GCD 主线程通信
4. Timer
- NSTimer 和 CADisplayLink 都依赖 RunLoop
5. Observer(观察者)
- 监听 RunLoop 状态变化,如将要进入、即将处理事件、即将休眠等
6. Port
- 线程通信载体,配合 Source1 使用
二、RunLoop 与线程保活
1. 子线程默认行为
任务执行完即退出,因为没有 RunLoop。
2. 线程保活方式
1 | - (void)startThread { |
3. 注意事项
run
会阻塞线程。- RunLoop 需要至少一个 Input Source 否则会立刻退出。
三、RunLoop 的实际应用(含示例)
1. 保持线程不退出
后台日志收集/解码任务中使用 RunLoop 保活线程。
2. 事件响应机制
如 Touch、Button 点击,通过 Source1 分发给主线程 RunLoop。
3. 定时器
NSTimer/CADisplayLink 依赖 RunLoop 触发。
4. GCD 主队列回调延迟
主线程卡顿时延迟执行,原因是 GCD 回调依赖 Source1。
5. UI 滚动与事件隔离
滚动 UIScrollView 时切换 Mode,暂停定时器触发。
6. AutoreleasePool 管理
RunLoop 每次循环自动创建/释放 pool,防止泄露。
7. 线程间通信
基于 Port 的消息传递,结合 Source1 实现。
四、RunLoop 实现原理
RunLoop 本质是一个基于事件循环的结构:
1 | while (!stop) { |
核心机制:
模块 | 说明 |
---|---|
mach_port | 底层通信机制 |
Source0 | 自定义事件 |
Source1 | 系统事件(如 GCD) |
Timer | 定时任务 |
Observer | 状态监听 |
Mode | 事件隔离与切换模式 |
Mode 与 Input Source 关系结构:
1 | RunLoop |
五、总结
分类 | 应用 |
---|---|
UI交互 | 事件响应、触摸分发、主队列 GCD |
多线程 | 线程保活、线程通信 |
性能优化 | 滚动时暂停动画 |
内存管理 | 自动释放池管理 |
动画处理 | CADisplayLink 刷新帧率 |