RunLoop的事件隊(duì)列
-
每次運(yùn)行RunLoop, 線程中的RunLoop會(huì)自動(dòng)處理線程中的任務(wù), 并且通知觀察者, 匯報(bào)當(dāng)前的狀態(tài), 順序如下
- 通知觀察者RunLoop已經(jīng)啟動(dòng)
- 通知觀察者任何即將要開(kāi)啟的定時(shí)器
- 通知觀察者任何即將要啟動(dòng)的非基于端口的事件源
- 啟動(dòng)任何準(zhǔn)備好的非基于端口的事件源
- 如果基于端口的事件源準(zhǔn)備好并處于等待狀態(tài), 就立即啟動(dòng), 并且進(jìn)入步驟9
- 通知觀察者線程即將進(jìn)入休眠
- 將線程置于休眠狀態(tài), 直至以下事件的發(fā)生
- 某一事件到達(dá)基于端口的源事件
- 定時(shí)器啟動(dòng)
- RunLoop設(shè)置的事件已經(jīng)超時(shí)
- RunLoop被顯式喚醒
- 通知觀察者線程即將被喚醒
- 處理事件
- 如果用戶定義的定時(shí)器啟動(dòng), 處理定時(shí)器事件并且重啟RunLoop, 然后進(jìn)入步驟2
- 如果輸入源啟動(dòng), 傳遞響應(yīng)的信息
- 如果RunLoop被現(xiàn)實(shí)喚醒, 并且事件還沒(méi)超時(shí), 重啟RunLoop, 進(jìn)入步驟2
- 通知觀察者RunLoop結(jié)束
-
代碼解釋
// 用DefaultMode啟動(dòng) void CFRunLoopRun(void) { CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); } // 用指定的Mode啟動(dòng)嫡霞,允許設(shè)置RunLoop超時(shí)時(shí)間 int CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean stopAfterHandle) { return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); } // RunLoop的實(shí)現(xiàn) int CFRunLoopRunSpecific(runloop, modeName, seconds, stopAfterHandle) { // 首先根據(jù)modeName找到對(duì)應(yīng)mode CFRunLoopModeRef currentMode = __CFRunLoopFindMode(runloop, modeName, false); // 如果mode里沒(méi)有source/timer/observer, 直接返回。 if (__CFRunLoopModeIsEmpty(currentMode)) return; // 1. 通知 Observers: RunLoop 即將進(jìn)入 loop法希。 __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopEntry); // 內(nèi)部函數(shù)膘滨,進(jìn)入loop __CFRunLoopRun(runloop, currentMode, seconds, returnAfterSourceHandled) { Boolean sourceHandledThisLoop = NO; int retVal = 0; do { // 2. 通知 Observers: RunLoop 即將觸發(fā) Timer 回調(diào)颜说。 __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeTimers); // 3. 通知 Observers: RunLoop 即將觸發(fā) Source0 (非port) 回調(diào)。 __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeSources); // 執(zhí)行被加入的block __CFRunLoopDoBlocks(runloop, currentMode); // 4. RunLoop 觸發(fā) Source0 (非port) 回調(diào)。 sourceHandledThisLoop = __CFRunLoopDoSources0(runloop, currentMode, stopAfterHandle); // 執(zhí)行被加入的block __CFRunLoopDoBlocks(runloop, currentMode); // 5. 如果有 Source1 (基于port) 處于 ready 狀態(tài)躲撰,直接處理這個(gè) Source1 然后跳轉(zhuǎn)去處理消息针贬。 if (__Source0DidDispatchPortLastTime) { Boolean hasMsg = __CFRunLoopServiceMachPort(dispatchPort, &msg) if (hasMsg) goto handle_msg; } // 通知 Observers: RunLoop 的線程即將進(jìn)入休眠(sleep)击费。 if (!sourceHandledThisLoop) { __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeWaiting); } // 7. 調(diào)用 mach_msg 等待接受 mach_port 的消息。線程將進(jìn)入休眠, 直到被下面某一個(gè)事件喚醒桦他。 // ? 一個(gè)基于 port 的Source 的事件蔫巩。 // ? 一個(gè) Timer 到時(shí)間了 // ? RunLoop 自身的超時(shí)時(shí)間到了 // ? 被其他什么調(diào)用者手動(dòng)喚醒 __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort) { mach_msg(msg, MACH_RCV_MSG, port); // thread wait for receive msg } // 8. 通知 Observers: RunLoop 的線程剛剛被喚醒了。 __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopAfterWaiting); // 收到消息快压,處理消息圆仔。 handle_msg: // 9.1 如果一個(gè) Timer 到時(shí)間了,觸發(fā)這個(gè)Timer的回調(diào)蔫劣。 if (msg_is_timer) { __CFRunLoopDoTimers(runloop, currentMode, mach_absolute_time()) } // 9.2 如果有dispatch到main_queue的block坪郭,執(zhí)行block。 else if (msg_is_dispatch) { __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); } // 9.3 如果一個(gè) Source1 (基于port) 發(fā)出事件了脉幢,處理這個(gè)事件 else { CFRunLoopSourceRef source1 = __CFRunLoopModeFindSourceForMachPort(runloop, currentMode, livePort); sourceHandledThisLoop = __CFRunLoopDoSource1(runloop, currentMode, source1, msg); if (sourceHandledThisLoop) { mach_msg(reply, MACH_SEND_MSG, reply); } } // 執(zhí)行加入到Loop的block __CFRunLoopDoBlocks(runloop, currentMode); if (sourceHandledThisLoop && stopAfterHandle) { // 進(jìn)入loop時(shí)參數(shù)說(shuō)處理完事件就返回歪沃。 retVal = kCFRunLoopRunHandledSource; } else if (timeout) { // 超出傳入?yún)?shù)標(biāo)記的超時(shí)時(shí)間了 retVal = kCFRunLoopRunTimedOut; } else if (__CFRunLoopIsStopped(runloop)) { // 被外部調(diào)用者強(qiáng)制停止了 retVal = kCFRunLoopRunStopped; } else if (__CFRunLoopModeIsEmpty(runloop, currentMode)) { // source/timer/observer一個(gè)都沒(méi)有了 retVal = kCFRunLoopRunFinished; } // 如果沒(méi)超時(shí),mode里沒(méi)空嫌松,loop也沒(méi)被停止沪曙,那繼續(xù)loop。 } while (retVal == 0); } // 10. 通知 Observers: RunLoop 即將退出萎羔。 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); }
-
圖解
-
RunLoop的一般應(yīng)用
- NSTimer和GCD定時(shí)器
- PerformSelector: afterDelay
- 當(dāng)調(diào)用這個(gè)方法的時(shí)候, 實(shí)際內(nèi)部會(huì)創(chuàng)建一個(gè)Timer并且添加到當(dāng)前的RunLoop中, 如果當(dāng)前線程沒(méi)有RunLoop, 這個(gè)方法也就會(huì)失效
- 在子線程中開(kāi)啟一個(gè)RunLoop, 做為常駐線程
- 自動(dòng)釋放池
- 手勢(shì)識(shí)別等等