1. Runloop 的使用场景
-
监测卡顿(Matrix):创建两个观察者runLoopObserver,添加到主线程的 common 模式,标记 Runloop 的开始和结束两种状态;然后创建一个子线程定期检查主线程的 Runloop 状态,如果主线程 runloop 停留在「进入睡眠前」或者「唤醒后」的状态超过 x 秒,就判断为出现卡顿,此时要 dump 出堆栈信息,上报服务端
-
触摸事件响应:用户触摸屏幕产生触摸事件,操作系统将事件放到队列中,主线程的 Runloop 不断检查事件队列中是否有待处理的事件(如果有就传给 UIApplication 处理),官方文档就是这么说的
-
手势识别
-
刷新页面:如果页面 View 发生改变,调用
setNeedsDisplay
orsetNeedsDisplayInRect:
函数来使这个 View 失效,系统知道后,会在当前 Runloop 结束后,对这个 View 进行重新绘制 (页面刷新相关的官方文档 -
performSelector
-
定时器 NSTimer:timer 注册后,Runloop 会在对应时间点设置好事件,时间点到了后再去执行对应注册的函数
-
GCD 中的 dispatch_async:使用时,libDispatch 向主线程的 Runloop 发送消息,Runloop 拿到对应的 block,在
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
执行 9.** AFNetworking2.0 的线程保活**:子线程获取到 Runloop,给这个 Runloop 添加了一个 Port,这个子线程就能一直保留着,不会结束。 -
AsyncDisplayKit:
2. Runloop 跟线程的关系
- 每个线程有且只有一个与之对应的 Runloop。
- 主线程的 Runloop 系统会自动开启,自己创建子线程,获取到 Runloop 后需要自己手动去开启 Runloop
- Runloop 不允许直接创建,而是通过函数 CFRunLoopGetCurrent (在子线程里调用) 和 CFRunLoopGetMain (获取主线程的 Runloop)。Runloop 会在子线程结束的时候销毁。