RunLoop是什么
RunLoop是事件接收和分發(fā)機(jī)制的一個實(shí)現(xiàn),是系統(tǒng)中和線程相關(guān)的基礎(chǔ)框架的組成部分;
一個RunLoop就是一個事件循環(huán)(do…while),用來不停的調(diào)度工作及處理輸入事件,提供一個消息機(jī)制處理模式
注:處理的事件大致分為:
source0響應(yīng):CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
source1響應(yīng):x__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
GCD主隊(duì)列:CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
observe源:CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
timer:CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION
block:CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
RunLoop和線程的關(guān)系
通過對CFRunLoopGetMain源碼中
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
這段代碼可以看出,RunLoop和線程的關(guān)系,它們是一一對應(yīng)的,被保存在一個字典中,并且RunLoop的生成是以線程為參數(shù)的,即RunLoop是依賴于線程的.
注:子線程的RunLoop默認(rèn)不開啟
Timer和RunLoop
Timer的運(yùn)行依賴于RunLoop
RunLoop源碼解析
主要研究對象:
CFRunloop
CFRunloopMode
CFRunloopSource
CFRunloopTimer
CFRunloopObserver
CFRunLoopRef lp = CFRunLoopGetCurrent();
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(ref);
NSLog(@“獲取當(dāng)前的RunLoopMode:%@“,mode);
CFArrayRef modeAry = CFRunLoopCopyAllModes(lp);
NSLog(@“獲取當(dāng)前的所有Mode:%@“,modeAry);
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;
};
RunLoop結(jié)構(gòu)體信息如上,其中我們主要關(guān)注的是_pthread、_commonModes、_commonModeItems、_currentMode
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
RunLoopMode結(jié)構(gòu)體信息如上,其中我們比較關(guān)注的是_source0(CFMutableSetRef)、_source1(CFMutableSetRef)、_observes(CFMutableArrayRef)、_timers(CFMutableArrayRef)
通過這兩個結(jié)構(gòu)體,很好的解釋了下面的RunLoop機(jī)制圖:

observer與runLoop
監(jiān)聽RunLoop狀態(tài)
source與RunLoop
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order; /* immutable */
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
結(jié)構(gòu)體信息如上
source0:處理App內(nèi)部事件,如UIEvent
source1:端口通信,用于線程之間通信
然后我們再來看下,Timer如何加到RunLoop的,又是如何被調(diào)用的
static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
CFTypeRef item = (CFTypeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
}
}
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
...
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlt);
…
} else {
…
}
__CFRunLoopUnlock(rl);
}
將timer加入_commonModeItems,然后通過下面函數(shù)
CFRunLoopRun-> CFRunLoopRunSpecific->__CFRunLoopRun-> __CFRunLoopDoBlocks
最后找到代碼:
if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
// timer 加入的mode 和 我們當(dāng)前mode是否相同
// 相同事務(wù)就可以執(zhí)行
doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
} else {
doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
}
再到下面代碼,最終執(zhí)行事務(wù)
if (doit) {
if (prev) prev->_next = item;
if (curr == head) head = item;
if (curr == tail) tail = prev;
void (^block)(void) = curr->_block;
CFRelease(curr->_mode);
free(curr);
if (doit) {
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
did = true;
}
Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
}
生活如此美好,今天就點(diǎn)到為止。。。