在main函数中调用CFRunLoopRun();之后的测试代码还会打印吗?
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
CFRunLoopRun();
NSLog(@"test CFRunLoopRun");
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
答案是不会,代码会一直在runloop的do while循环中等待,无法执行到测试的打印代码。这就是线程保活的关键
分析下源码:
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
可以看到在runloop没有停止过结束的情况下,runloop一直在do while循环
do while内部逻辑(看注释):
(......处删掉了部分代码,为了看起来逻辑简洁)
//CFRunLoopRunSpecific简化后的代码
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
......
//获取当前mode
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
//判断当前mode是否为空(代码见下一段)
//判断条件:是否存在sources0,sources1,timers其中一种(如果都为空,runloop就会退出循环,主线程不判断sources和timers,具体原因看下一段代码的注释)
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
Boolean did = false;
......
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
......
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
......
return result;
}
// expects rl and rlm locked
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
CHECK_FOR_FORK();
if (NULL == rlm) return true;
#if TARGET_OS_WIN32
if (0 != rlm->_msgQMask) return false;
#endif
#if __HAS_DISPATCH__
//这里判断是否是主线程,如果是主线程,就直接返回 了false,不进行下面的判断,这就是主线程和其他线程的判断区别(因此主线程的runloop不会退出)
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)) return false; // represents the libdispatch main queue
#endif
if (NULL == rlm) return true;
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;
......
return true;
}
网友评论