__CFRunLoopRun是內(nèi)部私有方法,只在CFRunLoopRunSpecific
中一處調(diào)用
- 方法聲明
/**
* @param CFRunLoopRef : rl
* @param CFRunLoopModeRef : rlm
* @param CFTimeInterval : seconds
* @param Boolean: stopAfterHandle
* @param CFRunLoopModeRef : previousMode
*/
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode)
- 返回值類型
/* Reasons for CFRunLoopRunInMode() to Return */
typedef CF_ENUM(SInt32, CFRunLoopRunResult) {
kCFRunLoopRunFinished = 1,
kCFRunLoopRunStopped = 2,
kCFRunLoopRunTimedOut = 3,
kCFRunLoopRunHandledSource = 4
};
kCFRunLoopRunFinished 和 kCFRunLoopRunStopped 會終止循環(huán)接剩。
分段解析
- 1妖碉、輸入?yún)?shù)檢查室梅,Stoped直接返回
// runloop 的狀態(tài)是否是Stopped
if (__CFRunLoopIsStopped(rl))
{
__CFRunLoopUnsetStopped(rl);
return kCFRunLoopRunStopped;
}
// runloopMode 的狀態(tài)是否是Stopped
else if (rlm->_stopped)
{
rlm->_stopped = false;
return kCFRunLoopRunStopped;
}
- 2浙芙、 GCD 隊(duì)列的端口設(shè)置
if ( 隊(duì)列安全libdispatchQSafe &&
isMainRunloop &&
CurrentRunLoopMode在 _commonModes 的set集合中 ) { dispatchPort 設(shè)置為 主線程 runloop 所關(guān)聯(lián)的的通信端口
}
mach_port_name_t dispatchPort = MACH_PORT_NULL;
Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name))
dispatchPort = _dispatch_get_main_queue_port_4CF();
- 3蹂风、超時(shí)時(shí)長操作: 使用的是GCD的Timer喜命。
dispatch_source_t timeout_timer = NULL;
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
if (seconds <= 0.0)
{ // instant timeout
seconds = 0.0;
timeout_context->termTSR = 0ULL;
}
else if (seconds <= TIMER_INTERVAL_LIMIT)
{
dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_retain(timeout_timer);
timeout_context->ds = timeout_timer;
timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
dispatch_resume(timeout_timer);
}
else
{ // infinite timeout
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
- 4沟沙、進(jìn)入 do - while 循環(huán)河劝,直到 reVal 不為 0 。
// 偽代碼矛紫,轉(zhuǎn)自·孫源@sunnyxx·的PPT
SetupThisRunLoopRunTimeoutTimer(); // by GCD timer
do {
__CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
__CFRunLoopDoObservers(kCFRunLoopBeforeSources);
__CFRunLoopDoBlocks();
__CFRunLoopDoSource0();
CheckIfExistMessagesInMainDispatchQueue(); // GCD
__CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);
var wakeUpPort = SleepAndWaitForWakingUpPorts();
// mach_msg_trap
// Zzz...
// Received mach_msg, wake up
__CFRunLoopDoObservers(kCFRunLoopAfterWaiting);
// Handle msgs
if (wakeUpPort == timerPort) {
__CFRunLoopDoTimers();
} else if (wakeUpPort == mainDispatchQueuePort) { // GCD
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
} else {
__CFRunLoopDoSource1();
}
__CFRunLoopDoBlocks();
} while (!stop && !timeout);
do - while.png
__CFRunLoopDoBlocks
處理的回調(diào)Blocks包括:
1. VC的聲明周期函數(shù)ViewDidLoad
赎瞎、viewWillAppear
……
2. 類似UICollectionViewDataSource的回調(diào)方法等- 處理喚醒時(shí)收到的消息,
Handler msgs
- 處理喚醒時(shí)收到的消息,
// Handler msgs
if(wakeUpPort == timerPort){
//如果是timer喚醒就去執(zhí)行timer
__CFRunLoopDoTimer();
}else if(wakeUpPort == mainDispatchQueuePort){
//GCD需要我颊咬,就去調(diào)GCD的事件
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE();
}else{
//比如說網(wǎng)絡(luò)來數(shù)據(jù)了就會用這個(gè)端口喚醒务甥,然后做數(shù)據(jù)處理
__CFRunloopDoSource1();
}
Handler msgs |
---|
處理timer |
執(zhí)行GCD丟進(jìn)MainThread的Blocks |
處理Source1 |