- 概念
- 数据结构
- 事件循环机制
- RunLoop 与 NSTimer
- RunLoop 与多线程
一、概念
- RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象
事件循环:
- 没有消息需要处理时,休眠以避免资源占用(用户态--> 内核态)
- 有消息需要处理,立刻被唤醒(内核态 --> 用户态)
系统调用相关指令如开关机等是在内核态的,程序一般运行在用户态的,绝大部分API都是用户态的
![](https://img.haomeiwen.com/i1350417/56ce03d7cea98483.jpg)
二、数据结构
NSRunLoop 是 CFRunLoop 的封装,提供了面相对象的API,其数据结构如下:
- CFRunLoop
- CFRunLoopMode
- Source/Timer/Observer
1、CFRunLoop
包含以下内容:
- pthread --- (RunLoop和线程一一对应)
- currentMode --- CFRunLoopMode
- modes --- NSMutableSet<CFRunLoopMode*>
- commonModes --- NSMutableSet<NSString*>
- commonModeItems --- 也是一个集合,包含多个 Observer(观察者)、Timer、Source
2、CFRunLoopMode
- name --- 名称,如 NSDefaultRunLoopMode 等
- sources0 -- 集合类型,无序的
- sources1 --- 集合类型
- observers --- 数组,有序的
- timers --- 数组
3、CFRunLoopSource
- source0 --- 需要手动唤醒线程
- source1 --- 具备唤醒线程的能力
4、CFRunLoopTimer
- 基于事件的定时器,和 NSTimer 是 toll-free bridged的。(即可以桥转换)
5、CFRunLoopObserver
观测时间点:
- kCFRunLoopEntry
- kCFRunLoopBeforeTimers
- kCFRunLoopBeforeSources
- kCFRunLoopBeforeWaiting --- 即将休眠,即将切换内核状态
- kCFRunLoopAfterWaiting --- 内核态切换到用户态不久之后发出
- kCFRunLoopExit
各个数据结构之间的关系
一对多的关系:
![](https://img.haomeiwen.com/i1350417/6f10687ebd5cb765.jpg)
RunLoop的Mode:
问题:怎样将Timer同时添加到两个mode?以保证mode切换的时候,不影响timer的使用
![](https://img.haomeiwen.com/i1350417/5a72c11b2db6c77c.jpg)
解决 :NSRunLoopCommonModes
NSRunLoopCommonModes的特殊性
- commonMode 不是实际存在的一种Mode
- 是同步 Source/Timer/Observer 到多个 Mode 中的一种技术方案
三、事件循环机制
![](https://img.haomeiwen.com/i1350417/0260b6eef5200d5d.jpg)
APP运行生命周期内RunLoop的整体事件循环机制
RunLoop的核心
![](https://img.haomeiwen.com/i1350417/5deabcb31db18bc1.jpg)
四、RunLoop 与 NSTimer
问题:滑动 TableView 时,定时器还会生效吗?
回答:不会生效,timer 默认加入到 defaultMode 中,滑动的时候,Mode 会从 kCFRunLoopDefaultMode 切换到 UITrackingRunLoopMode,不同的 Mode ,timer 不相关,所以不生效
解决:添加到 kCFRunLoopCommonMode 中
五、RunLoop 与多线程
- 线程是和 RunLoop 一一对应的
- 自己创建的线程默认是没有 RunLoop 的
怎样实现一个常驻线程
- 为当前线程开启一个 RunLoop
- 向该 RunLoop 中添加一个 Port/Source 等维持 RunLoop 的事件循环
- 启动该 RunLoop
代码实现:
运行的模式和资源添加的模式一定要是同一个
![](https://img.haomeiwen.com/i1350417/dc371318222e9bf0.jpg)
![](https://img.haomeiwen.com/i1350417/2f3538c17266be3e.jpg)
总结
- 什么是 RunLoop ,是怎样做到有事做事,没事休息的?
- RunLoop 与线程的关系?
- 如何实现常驻线程?
- 怎样保证子线程数据回来更新UI的时候,不打断用户的滑动操作?(把子线程抛给主线程的操作添加到 DefaultMode 下,此时滑动 UITrackingRunLoopMode 不受影响)
网友评论