RunLoop
RunLoop
是iOS
泉孩、OSX
開發(fā)中非惩纾基礎(chǔ)的一個(gè)概念谴忧,這篇文章將會(huì)從源碼的角度分析RunLoop
的概念已經(jīng)底層實(shí)現(xiàn)原理朴下。在iOS
中努咐,蘋果如何利用RunLoop
實(shí)現(xiàn)了自動(dòng)釋放池
苦蒿、延遲回調(diào)
殴胧、觸摸事件
和屏幕刷新
等功能,我們也將一一探索。
RunLoop的作用
- 保持程序的運(yùn)行
- 處理APP的各種事件(觸摸团滥,定時(shí)器竿屹,
performSelector
) - 節(jié)省CPU資源、提高程序的性能灸姊;該做事就做事拱燃,該休息就休息
RunLoop
的應(yīng)用非常廣泛,iOS
中多種任務(wù)的執(zhí)行都依賴RunLoop
力惯,下面是一些RunLoop
的call out
函數(shù)
block
:CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
NSTimer
:__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
SOURCE0
:__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
SOURCE1
:__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
GCD主隊(duì)列
:__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
observer源
:__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
官方文檔
RunLoop
的官方文檔在Threading Programming Guide
中碗誉。
OSX/iOS
系統(tǒng)中,提供了兩個(gè)RunLoop
對象NSRunLoop
和CFRunLoopRef
CFRunLoopRef
是在CoreFoundation
框架內(nèi)的父晶,它提供了純C
函數(shù)的API
哮缺,所有這些API
是線程安全
的
NSRunLoop
是基于CFRunLoopRef
的封裝,提供了面向?qū)ο蟮?code>API甲喝,但是這些API不是線程安全
的
CFRunLoopRef
的代碼是開源的尝苇,可以在這里下載
源碼分析
- 搜索
CFRunLoopRun
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
這就是一個(gè)do-while
循環(huán),這里最重要的就是CFRunLoopRunSpecific
方法埠胖。當(dāng)RunLoopRunStopped
或者RunLoopRunFinished
的時(shí)候才會(huì)跳出循環(huán)
- 查看
CFRunLoopRunSpecific
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
Boolean did = false;
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
CFRunLoopModeRef previousMode = rl->_currentMode;
rl->_currentMode = currentMode;
int32_t result = kCFRunLoopRunFinished;
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);//通知Observer糠溜,runloop即將進(jìn)來
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);//這是才是`runloop`執(zhí)行任務(wù)的地方
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);//通知Observer,runloop即將退出
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopPopPerRunData(rl, previousPerRun);
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
RunLoop和線程的關(guān)系
蘋果不允許直接創(chuàng)建RunLoop
直撤,它提供了兩個(gè)獲取的函數(shù)CFRunLoopGetMain()
和CFRunLoopGetCurrent ()
非竿,下面我們看一下這兩個(gè)函數(shù)的實(shí)現(xiàn)。
- 搜索
CFRunLoopGetMain
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
- 搜索
CFRunLoopGetCurrent
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
上面兩個(gè)函數(shù)谊惭,都調(diào)用了_CFRunLoopGet0
- 查看
_CFRunLoopGet0
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();//線程為空汽馋,設(shè)置為主線程
}
__CFLock(&loopsLock);
if (!__CFRunLoops) {//綁定主線程
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
// 進(jìn)行綁定 dict[@"pthread_main_thread_np"] = mainLoop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
CFRelease(mainLoop);
__CFLock(&loopsLock);
}
//綁定其他線程
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFUnlock(&loopsLock);
if (!loop) {
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
// don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
__CFUnlock(&loopsLock);
CFRelease(newLoop);
}
if (pthread_equal(t, pthread_self())) {
_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
}
}
return loop;
}
這個(gè)方法主要是創(chuàng)建runloop
,并把runloop
和對應(yīng)的線程通過key-value
的方式保存下來圈盔。
- 查看
__CFRunLoopCreate
static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
//創(chuàng)建一個(gè)CFRunLoopRef
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL);
if (NULL == loop) {
return NULL;
}
//下面是對`RunLoop`的賦值操作
(void)__CFRunLoopPushPerRunData(loop);
__CFRunLoopLockInit(&loop->_lock);
loop->_wakeUpPort = __CFPortAllocate();
if (CFPORT_NULL == loop->_wakeUpPort) HALT;
__CFRunLoopSetIgnoreWakeUps(loop);
loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
loop->_commonModeItems = NULL;
loop->_currentMode = NULL;
loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
loop->_blocks_head = NULL;
loop->_blocks_tail = NULL;
loop->_counterpart = NULL;
loop->_pthread = t;
#if DEPLOYMENT_TARGET_WINDOWS
loop->_winthread = GetCurrentThreadId();
#else
loop->_winthread = 0;
#endif
rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
return loop;
}
- 搜索
__CFRunLoop {
查看__CFRunLoop
結(jié)構(gòu)體
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
可以看到里面的Modes
豹芯,說明runloop
有多個(gè)mode
切換,還有一個(gè)_currentMode
表示當(dāng)前mode
Mode
在斷點(diǎn)處進(jìn)行
LLDB
調(diào)試
(lldb) po CFRunLoopCopyCurrentMode(mainRunLoop)
kCFRunLoopDefaultMode
(lldb) po CFRunLoopCopyAllModes(mainRunLoop)
<__NSArrayM 0x6000007a4930>(
UITrackingRunLoopMode,//追蹤ScrollView的滑動(dòng)狀態(tài)
GSEventReceiveRunLoopMode,//處理事件
kCFRunLoopDefaultMode,
kCFRunLoopCommonModes
)
(lldb)
可以看出mainRunLoop
里面有四種Mode
驱敲,這也對應(yīng)了上面铁蹈,一個(gè)runLoop
可以有多種mode
,可以在各種mode
之間切換
CFRunLoopMode
和CFRunLoop
大致源碼如下:
struct __CFRunLoopMode {
...
CFStringRef _name;//mode name , 例如@"kCFRunLoopDefaultMode"
CFMutableSetRef _sources0;//sources0 set
CFMutableSetRef _sources1;//sources1 set
CFMutableArrayRef _observers;//_observers array
CFMutableArrayRef _timers;//_timers array
CFMutableDictionaryRef _portToV1SourceMap;
...
};
struct __CFRunLoop {//RunLoop里面存在modes
...
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
...
};
這里有個(gè)概念叫commonModes
众眨,一個(gè)mode
可以將自己標(biāo)記為“Common”
屬性(通過將其modeName
加入到RunLoop
的commonModes
中)握牧。每當(dāng)RunLoop
的內(nèi)容發(fā)生變化時(shí),RunLoop
都會(huì)自動(dòng)將_commonModeItems
中的Source/Observer/Timer
同步到具有“Common”
標(biāo)記的所有mode中娩梨。
主線程的RunLoop
中有兩個(gè)預(yù)置的mode
: kCFRunLoopDefaultMode
和UITrackingRunLoopMode
沿腰,這兩個(gè)都已經(jīng)被標(biāo)記“Common”
屬性。DefaultMode
是APP
平時(shí)所處的狀態(tài)狈定,TrackingRunLoopMode
是追蹤ScrollView
滑動(dòng)時(shí)的狀態(tài)颂龙。當(dāng)你創(chuàng)建一個(gè)timer
加入到DefaultMode
习蓬,正常情況下timer
可以得到回調(diào),但當(dāng)你滑動(dòng)ScrollView
的時(shí)候措嵌,RunLoop
會(huì)切換到TrackingRunLoopMode
躲叼,這時(shí)的timer
就不會(huì)回調(diào),也不會(huì)影響滑動(dòng)操作企巢。
有時(shí)候你需要一個(gè)timer
在兩個(gè)mode
中都能得到回調(diào)枫慷,一種方法是將timer
分別加入這兩個(gè)mode
,還有一種方法就是將timer
加入到頂層的commonModeItems
中浪规,被
RunLoop
自動(dòng)更新到具有“Common”
的mode
中去
面試題
NSTimer
結(jié)果是不會(huì)打印或听,子線的
runloop
默認(rèn)是不啟動(dòng)的,NSTimer
不會(huì)執(zhí)行block
任務(wù)笋婿。
解決方法:
加上這一句代碼神帅,開啟
runLoop
即可
不知道大家有沒有這樣的疑問,NSTimer
為什么要依賴于runLoop
才可以執(zhí)行呢萌抵?
在斷點(diǎn)處打印堆棧信息找御,可以看到我們熟悉的
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
- 在源碼中搜索
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func, CFRunLoopTimerRef timer, void *info) {
if (func) {
func(timer, info);
}
asm __volatile__(""); // thwart tail-call optimization
}
在這里執(zhí)行了Timer
的任務(wù)回調(diào)函數(shù),其實(shí)執(zhí)行任務(wù)要從下面的-[NSRunLoop(NSRunLoop) run]
開始
-
搜索
__CFRunLoopRun
找到一個(gè)很長的方法
往下看
這里是處理block
和observer
的
這里doTimers绍填,處理timer
查看
__CFRunLoopDoTimers
static Boolean __CFRunLoopDoTimers(CFRunLoopRef rl, CFRunLoopModeRef rlm, uint64_t limitTSR) { /* DOES CALLOUT */
Boolean timerHandled = false;
CFMutableArrayRef timers = NULL;
for (CFIndex idx = 0, cnt = rlm->_timers ? CFArrayGetCount(rlm->_timers) : 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx);
if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
if (rlt->_fireTSR <= limitTSR) {
if (!timers) timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(timers, rlt);
}
}
}
for (CFIndex idx = 0, cnt = timers ? CFArrayGetCount(timers) : 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timers, idx);
Boolean did = __CFRunLoopDoTimer(rl, rlm, rlt);
timerHandled = timerHandled || did;
}
if (timers) CFRelease(timers);
return timerHandled;
}
循環(huán)_timers
里面的timer
霎桅,執(zhí)行__CFRunLoopDoTimer
方法
- 查看
__CFRunLoopDoTimer
往下可以找到我們熟悉的__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
函數(shù)
最后我們查看一下timer
在下層的結(jié)構(gòu)
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval; /* immutable */
CFTimeInterval _tolerance; /* mutable */
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; /* immutable */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
NSTimer
里面有_runLoop
和_callout
,拿到了timer
對象就能準(zhǔn)確執(zhí)行
這些方法執(zhí)行了Timer
的任務(wù)讨永。那又是哪個(gè)方法將Timer
加到了NSRunLoop
呢?
我們記得NSRunLoop
有一個(gè)addTimer:forMode:
的方法滔驶,在源碼中搜索addTimer
-
搜索
addTimer
從這里可以看出橱夭,Source
铣缠、Observer
、Timer
都要加入RunLoop
查看
CFRunLoopAddTimer
方法
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
//屏蔽非空
__CFRunLoopLock(rl);//加鎖
if (modeName == kCFRunLoopCommonModes) {//當(dāng)是CommonMode
//_commonModes為空 賦一個(gè)默認(rèn)值
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
//_commonModeItems為空 賦一個(gè)默認(rèn)值
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlt);//把timer加入 _commonModeItems
if (NULL != set) {//set 不為空 加到`CommonModes`中去
CFTypeRef context[2] = {rl, rlt};
/* add new item to all common-modes */
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
}
else {
//根據(jù)name 和runloop匹配 CFRunLoopModeRef
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm) {
if (NULL == rlm->_timers) {
CFArrayCallBacks cb = kCFTypeArrayCallBacks;
cb.equal = NULL;
rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
}
}
if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
__CFRunLoopTimerLock(rlt);
if (NULL == rlt->_runLoop) {
rlt->_runLoop = rl;
} else if (rl != rlt->_runLoop) {
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
return;
}
CFSetAddValue(rlt->_rlModes, rlm->_name);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
__CFRepositionTimerInMode(rlm, rlt, false);//將timer添加到mode中
__CFRunLoopTimerFireTSRUnlock();
if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
// Normally we don't do this on behalf of clients, but for
// backwards compatibility due to the change in timer handling...
if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
}
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
根據(jù)modeName
將timer
加到__CFRunLoopMode
的_timers
中去
- 搜索
__CFRepositionTimerInMode
static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) {
if (!rlt) return;
CFMutableArrayRef timerArray = rlm->_timers;
if (!timerArray) return;
Boolean found = false;
// If we know in advance that the timer is not in the array (just being added now) then we can skip this search
if (isInArray) {
CFIndex idx = CFArrayGetFirstIndexOfValue(timerArray, CFRangeMake(0, CFArrayGetCount(timerArray)), rlt);
if (kCFNotFound != idx) {
CFRetain(rlt);
CFArrayRemoveValueAtIndex(timerArray, idx);
found = true;
}
}
if (!found && isInArray) return;
CFIndex newIdx = __CFRunLoopInsertionIndexInTimerArray(timerArray, rlt);
CFArrayInsertValueAtIndex(timerArray, newIdx, rlt);//將timer 加到_timers數(shù)組
__CFArmNextTimerInMode(rlm, rlt->_runLoop);
if (isInArray) CFRelease(rlt);
}
這個(gè)函數(shù)主要是添加timer
Observer
-
Observer
結(jié)構(gòu)體
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
-
CFRunLoopAddObserver
-
__CFRunLoopDoObservers
與Timer
的原理基本一致屎即。
__CFRunLoopRun詳解
CFRunLoopRun
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);// 科學(xué)計(jì)數(shù)1.0e10
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
每次runloop
循環(huán)锻霎,傳入了一個(gè)循環(huán)時(shí)間
-
__CFRunLoopRun
在這里面也有一個(gè)計(jì)時(shí)器用來記錄時(shí)間著角,由于NSTimer
是依賴于RunLoop
的,在這里顯然不適用旋恼。這里使用的是dispatch_source_t
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 { //超時(shí)
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
- 將代碼折疊起來查看整體結(jié)構(gòu)
do-while
循環(huán)才是我們研究的重點(diǎn)吏口,
下面是runloop
方法的流程圖和主要代碼。
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
/// 首先根據(jù)modeName找到對應(yīng)mode
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
/// 通知 Observers: RunLoop 即將進(jìn)入 loop冰更。
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
/// 內(nèi)部函數(shù)产徊,進(jìn)入loop
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
/// 通知 Observers: RunLoop 即將退出。
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
return result;
}
/// 核心函數(shù)
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
int32_t retVal = 0;
do { // itmes do
/// 通知 Observers: 即將處理timer事件
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
/// 通知 Observers: 即將處理Source事件
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources)
/// 處理Blocks
__CFRunLoopDoBlocks(rl, rlm);
/// 處理sources0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
/// 處理sources0返回為YES
if (sourceHandledThisLoop) {
/// 處理Blocks
__CFRunLoopDoBlocks(rl, rlm);
}
/// 判斷有無端口消息(Source1)
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
/// 處理消息
goto handle_msg;
}
/// 通知 Observers: 即將進(jìn)入休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
/// 等待被喚醒
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
/// 通知 Observers: 被喚醒蜀细,結(jié)束休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:
if (被Timer喚醒) {
/// 處理Timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())舟铜;
} else if (被GCD喚醒) {
/// 處理gcd
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
} else if (被Source1喚醒) {
/// 被Source1喚醒,處理Source1
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)
}
/// 處理block
__CFRunLoopDoBlocks(rl, rlm);
if (sourceHandledThisLoop && stopAfterHandle) {
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
retVal = kCFRunLoopRunFinished;
}
} while (0 == retVal);
return retVal;
}
// main dispatch queue
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
// __CFRunLoopDoObservers
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
// __CFRunLoopDoBlocks
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__
// __CFRunLoopDoSources0
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
// __CFRunLoopDoSource1
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
// __CFRunLoopDoTimers
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__