之前看过不少别人博客里对CFRunLoop源码的分析,但自己一直没有去看过,今天回顾相关知识时,决定自己去看看相关的源码实现,确实又有了一些新的认识与收获.
CFRunLoopRun、CFRunLoopRunInMode
首先是两个简单的入口函数
//两个函数分别是让runloop跑在kCFRunLoopDefaultMode下,与让runloop跑在指定mode下
//两个函数区别不大,最终都调用CFRunLoopRunSpecific
/*runloop同时只能跑在一个mode下,切换mode,要退出当前runloop
什么叫退出当前runloop?所谓的退出,通过源码有了更直观的认识,其实就是传递不同的modeName,
一遍一遍的跑CFRunLoopRunSpecific->CFRunLoopRun逻辑代码,每跑完一遍,就是所谓的退出,马上迎来下一次CFRunLoopRunInMode调用
*/
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
CFRunLoopRunSpecific
/*
参数1:传入runloop对象,实际传入的都是CFRunLoopGetCurrent
参数2:传入当前要运行的mode名称
参数3:runloop的超时时间
参数4:主要__CFRunLoopRun会用到,后面说
*/
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
//得到当前的mode对象
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
//看看是不是一个空mode,后面会简单分析__CFRunLoopModeIsEmpty实现
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode))
//通知进入kCFRunLoopEntry状态,,后面会简单看看__CFRunLoopDoObservers实现
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
//进入关键函数,__CFRunLoopRun
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
//通知进入kCFRunLoopExit状态
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
return result;
}
看看几个重要相关函数
__CFRunLoopModeIsEmpty
//就是看看这个mode里有没有source0、source1、timer,只要存在source0或source1或timer就不是空的.同时看看这个mode是不是属于当前的runloop
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false;
if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false;
if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false;
struct _block_item *item = rl->_blocks_head;
while (item) {
struct _block_item *curr = item;
item = item->_next;
Boolean doit = false;
if (CFStringGetTypeID() == CFGetTypeID(curr