我們都知道runloop是一個(gè)循環(huán),那么我有這么一個(gè)問(wèn)題,dispatch_get_main_queue()是在當(dāng)次循環(huán)還是下次循環(huán)執(zhí)行仓洼。于是座韵,進(jìn)行了下面這波測(cè)試和分析险绘。
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"1");
});
先通過(guò)監(jiān)聽(tīng)runloop的各個(gè)狀態(tài)來(lái)測(cè)試
void myRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
switch(activity)
{
// 即將進(jìn)入Loop
case kCFRunLoopEntry:
NSLog(@"run loop entry");
break;
case kCFRunLoopBeforeTimers://即將處理 Timer
NSLog(@"run loop before timers");
break;
case kCFRunLoopBeforeSources://即將處理 Source
NSLog(@"run loop before sources");
break;
case kCFRunLoopBeforeWaiting://即將進(jìn)入休眠
NSLog(@"run loop before waiting");
break;
case kCFRunLoopAfterWaiting://剛從休眠中喚醒
NSLog(@"run loop after waiting");
break;
case kCFRunLoopExit://即將退出Loop
NSLog(@"run loop exit");
break;
default:
break;
}
}
image.png
通過(guò)上面分析,感覺(jué)是下次循環(huán)誉碴。
image.png
CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE 這個(gè)東西是什么呢宦棺?
然后又去找了下源碼。
CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
CFRunloop is calling out to an abserver callback function
用于向外部報(bào)告 RunLoop 當(dāng)前狀態(tài)的更改黔帕,框架中很多機(jī)制都由 RunLoopObserver 觸發(fā)代咸,如 CAAnimation
CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
CFRunloop is calling out to a block
消息通知、非延遲的perform成黄、dispatch調(diào)用呐芥、block回調(diào)逻杖、KVO
CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
CFRunloop is servicing the main desipatch queue
CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION
CFRunloop is calling out to a timer callback function
延遲的perform, 延遲dispatch調(diào)用
CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
CFRunloop is calling out to a source 0 perform function
處理App內(nèi)部事件、App自己負(fù)責(zé)管理(觸發(fā))思瘟,如UIEvent荸百、CFSocket。普通函數(shù)調(diào)用滨攻,系統(tǒng)調(diào)用
CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION
CFRunloop is calling out to a source 1 perform function
看到這里好像還不能知道為什么够话。
{
// 1.1 通知Observers,即將進(jìn)入RunLoop
// 此處有Observer會(huì)創(chuàng)建AutoreleasePool: _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopEntry);
do {
// 2.1 通知 Observers: 即將觸發(fā) Timer 回調(diào)光绕。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeTimers);
// 2.2 通知 Observers: 即將觸發(fā) Source (非基于port的,Source0) 回調(diào)更鲁。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources);
// 執(zhí)行Block
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
// 2.3 觸發(fā) Source0 (非基于port的) 回調(diào)。
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0);
// 執(zhí)行Block
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
// 3.1 通知Observers奇钞,即將進(jìn)入休眠
// 此處有Observer釋放并新建AutoreleasePool: _objc_autoreleasePoolPop(); _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeWaiting);
// 3.2 sleep to wait msg.
mach_msg() -> mach_msg_trap();
// 3.3 通知Observers澡为,線程被喚醒
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopAfterWaiting);
// 4.1 如果是被Timer喚醒的,回調(diào)Timer
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(timer);
// 4.2 如果是被dispatch喚醒的景埃,執(zhí)行所有調(diào)用 dispatch_async 等方法放入main queue 的 block
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(dispatched_block);
// 4.3 如果如果Runloop是被 Source1 (基于port的) 的事件喚醒了媒至,處理這個(gè)事件
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(source1);
// 5. 退出判斷函數(shù)調(diào)用棧無(wú)顯示
} while (...);
// 6. 通知Observers,即將退出RunLoop
// 此處有Observer釋放AutoreleasePool: _objc_autoreleasePoolPop();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopExit);
}
看完上面的內(nèi)容谷徙,我覺(jué)得可以這么理解拒啰,通過(guò)dispatch_asyn注冊(cè)到observer中,當(dāng)runloop下次循環(huán)的時(shí)候完慧,執(zhí)行所有通過(guò)dispatch_asyn添加進(jìn)去的事件谋旦。
所以應(yīng)該是下次循環(huán)。
看一下下面的代碼屈尼,理解可能會(huì)更深一點(diǎn)册着。
/**
* 運(yùn)行run loop
*
* @param rl 運(yùn)行的RunLoop對(duì)象
* @param rlm 運(yùn)行的mode
* @param seconds run loop超時(shí)時(shí)間
* @param stopAfterHandle true:run loop處理完事件就退出 false:一直運(yùn)行直到超時(shí)或者被手動(dòng)終止
* @param previousMode 上一次運(yùn)行的mode
*
* @return 返回4種狀態(tài)
*/
static int32_t __CFRunLoopRun(CFRunLoopRef rl,
CFRunLoopModeRef rlm,
CFTimeInterval seconds,
CFRunLoopModeRef previousMode) {
// 借助GCD timer,設(shè)置runloop的超時(shí)時(shí)間
dispatch_source_t timeout_timer = ...
// 超時(shí)回調(diào)函數(shù) __CFRunLoopTimeout
dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
// 超時(shí)取消函數(shù) __CFRunLoopTimeoutCancel
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
// 進(jìn)入do while循環(huán)脾歧,開(kāi)始run
int32_t retVal = 0; // runloop run返回值甲捏,默認(rèn)為0,會(huì)在do while中根據(jù)情況被修改鞭执,當(dāng)不為0時(shí)司顿,runloop退出
do{
mach_port_t livePort = MACH_PORT_NULL; // 用于記錄喚醒休眠的RunLoop的mach port,休眠前是NULL
__CFPortSet waitSet = rlm->_portSet; // 取當(dāng)前mode所需要監(jiān)聽(tīng)的mach port集合兄纺,用于喚醒runloop(__CFPortSet 實(shí)際上是unsigned int 類(lèi)型)
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); // 通知 即將處理 Timers
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); // 通知 即將處理 sources
// 處理提交到runloop的blocks
__CFRunLoopDoBlocks(rl, rlm);
// 處理 source0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
__CFRunLoopDoBlocks(rl, rlm); // 處理提交的runloop的block
}
// 如果有source1被signaled大溜,則不休眠,直接跳到handle_msg來(lái)處理source1
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
goto handle_msg;
}
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); // 通知observer before waiting
// ****** 開(kāi)始休眠 ******
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy); // 調(diào)用__CFRunLoopServiceMachPort, 監(jiān)聽(tīng)waitSet所指定的mach port端口集合, 如果沒(méi)有port message估脆,進(jìn)入 mach_msg_trap, RunLoop休眠,直到收到port message或者超時(shí)
// ****** 休眠結(jié)束 ******
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); // 通知observer钦奋, runloop醒了
handle_msg:; // 處理事件
// 根據(jù)喚醒RunLoop的livePort值,來(lái)進(jìn)行對(duì)應(yīng)邏輯處理
if (MACH_PORT_NULL == livePort) { // MACH_PORT_NULL: 可能是休眠超時(shí),啥都不做
CFRUNLOOP_WAKEUP_FOR_NOTHING();
// handle nothing
} else if (livePort == rl->_wakeUpPort) { // rl->_wakeUpPort: 被其他線程或進(jìn)程喚醒锨苏,啥都不做
CFRUNLOOP_WAKEUP_FOR_WAKEUP();
// do nothing on Mac OS
} else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) // rlm->_timerPort: 處理nstimer 消息
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer
__CFArmNextTimerInMode(rlm, rl);
}
}else if (livePort == dispatchPort) // dispatchPort:處理分發(fā)到main queue上的事件
{
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
}else { // 其余的疙教,肯定是各種source1 事件
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)
if (NULL != reply) { // 如果有需要回復(fù)soruce1的消息棺聊,則回復(fù)
(void)mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
}
}
// ****** 到這里就結(jié)束了對(duì)livePort的處理 ******
__CFRunLoopDoBlocks(rl, rlm); // 處理提交到runloop的blocks
// 檢查runloop是否需要退出
if (sourceHandledThisLoop && stopAfterHandle) { // case1. 指定了僅處理一個(gè)source 退出kCFRunLoopRunHandledSource
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) { // case2. RunLoop 超時(shí)
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) { // case3. RunLoop 被終止
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) { // case4. RunLoop Mode 被終止
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) { // case5. RunLoop Mode里面沒(méi)有任何要被處理的事件了(沒(méi)有source0伞租,source1, timer限佩,以及提交到當(dāng)前runloop mode的block)
retVal = kCFRunLoopRunFinished;
}
}while(0 == retVal);
// runloop循環(huán)結(jié)束葵诈,返回退出原因
return retVal;
}