先附个图<盗个图, 懒得自己画了-_-
> 图片来源, 同时这篇文章写的也超级详细, 推荐!!!
PS:图片里的顺序与源码顺序稍稍有点出入, 但是不影响整体的理解~
runloop整理:
1. runloop和线程是一对一的关系.
2. 主线程runloop程序启动自动获取; 子线程的runloop需要显示获取CFRunLoopGetCurrent().
3. 线程中的runloop在没有source、timer、obsever时, 会退出或者不进入循环.
4. 一次runloop对应一种mode, mode一共有4种, 公开的有2种, default & tracking 两种, 还有一种集合commonMode, 是前两种的集合
5. runloop mode {kCFRunLoopDefaultMode, UITrackingRunLoopMode}. 每种mode又分别可以包含3种modeItem {CFRunLoopSourceRef<source0, source1>, CFRunLoopTimerRef<timer>, CFRunLoopObserverRef<observer>}
6. runloop内有autoreleasepool的创建和销毁; 即将进入runloop会创建自动释放池, 在处理完source0和block后即将进入休眠时, 会销毁自动释放池并且再新建一个释放池; runloop退出时会销毁释放池.
7. runloop 处理事件流程:
1) 调用 CFRunLoopRunSpecific() 函数. 先判断runloop是否正在销毁或者 runloopmode为空, 若为空则不进入循环, 否则将rl->_currentMode设置为当前mode, 同时发送kCFRunLoopEntry的通知.
2) 进入 __CFRunLoopRun() 函数. 判断rl || rlm是否处于stop, 是则不进入循环, 否则继续.
3) 处理超时时间, 如果设置的时间在限制之内, 当超时时, 会向外部发送超时通知.
4) 进入do while 循环, 1先通知外部即将处理timer事件, 2再通知外部即将处理source事件
5) 3处理block<block是以单向链表的形式存储的>, __CFRunLoopDoBlocks() 内部会调用私有函数 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__
6) 4处理source0事件<UIEvent, CFSocket>, 如果有source0则再次调用__CFRunLoopDoBlocks处理block
7) 5发送即将进入休眠的通知, 同时进入休眠状态.
8) 6进入内部循环, 等待接收系统事件<source1>的唤醒. 若收到事件, 则跳出内部循环, 同时发送即将唤醒的通知
9) 7处理收到的消息, 如果是定时器<timer>则处理定时器事件; 如果是dispatch到main queue的block则调用 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ 执行block; 如果是source事件, 先判断是否有source1事件, 有则处理source1; 最后再处理一次block
10) 8判断一下retValue值, 如果是CFRunLoopRunResult其中一种状态, 则runloop运行循环继续; 否则为0则退出循环.