我对 RunLoop 的理解
我的理解,仔细分析这个图,RunLoop 的设计主要是为了异步处理事件。外部的事件触发只是唤醒 RunLoop,并非立即同步执行处理。唤醒后进入循环才逐一处理事件。
RunLoop 有两种类型的 Source:
- Input Sources,传递异步事件。
- Port-Based Sources (Source1),能够主动唤醒 RunLoop。
- Custom Input Sources (Source0),需要手动唤醒 RunLoop。
- Timer Sources,传递同步事件。
Observer 的状态流转:
所有状态:
kCFRunLoopEntry →
kCFRunLoopBeforeTimers →
kCFRunLoopBeforeSources →
kCFRunLoopBeforeWaiting →
kCFRunLoopAfterWaiting →
kCFRunLoopExit
休眠之前循环处理事件:
kCFRunLoopBeforeTimers →
kCFRunLoopBeforeSources →
kCFRunLoopBeforeTimers
唤醒之后开始处理事件:
kCFRunLoopAfterWaiting → kCFRunLoopBeforeTimers
大部分的UI事件回调都在
kCFRunLoopBeforeSources
之后,kCFRunLoopBeforeWaiting
之前,堆栈如图但,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
,这个方法执行在 kCFRunLoopBeforeWaiting
的 observer 里,堆栈如图一个 RunLoop 同一时刻只能处于一个 mode 中。common mode 只是一种标记,表示 common mode 中的 modes 共享 sources、timers、observers。
iOS 的 modes:
NSDefaultRunLoopMode
UITrackingRunLoopMode
NSRunLoopCommonModes(默认包括NSDefaultRunLoopMode和UITrackingRunLoopMode)
UIInitializationRunLoopMode
GSEventReceiveRunLoopMode
RunLoop的休眠可以看成是用户状态到内核状态的切换,而唤醒RunLoop就是内核状态到用户状态的切换。
RunLoop的实际应用
系统应用:
- AutoreleasePool,创建了两个 observer ,在监听里创建和释放自动释放池。
- 硬件事件响应,从 __CFRunLoopDoSource1 传到 __CFRunLoopDoSource0
- 手势识别
- 界面更新
- CFRunLoopPerformBlock,performSelecter
- NSTimer = CFRunLoopTimerRef
- dispatch_async(dispatch_get_main_queue(), block)
其他应用:
- NSURLConnection(线程保活)
- AsyncDisplayKit(界面刷新)
- 卡顿监控
- 通过密集执行代码改为一次RunLoop执行一次,可避免卡顿(如tableview图片加载)
Loading Comments...