RunLoop -- 运行逻辑
2020-04-11 本文已影响0人
踩坑小分队
直接分析下源码
CFRunLoopRef源码地址
通过打断点可以从 CFRunLoopRun 方法进行查看
/* rl, rlm are locked on entrance and exit */
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
// 当retVal == 0 的时候,进入do while循环.如果retVal一直值0则一直循环
int32_t retVal = 0;
do {
// 通知Observers,即将处理Timers
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 通知Observers,即将处理Sources
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 处理blocks
__CFRunLoopDoBlocks(rl, rlm);
// DoSources0处理Sources0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
// 判断处理的结果,如果为YES,进行block回调
if (sourceHandledThisLoop) {
__CFRunLoopDoBlocks(rl, rlm);
}
Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) {
msg = (mach_msg_header_t *)msg_buffer;
// 如果有Source1,就跳转到 handle_msg 处
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
goto handle_msg;
}
}
didDispatchPortLastTime = false;
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting))
// 通知Observer,马上要进行休眠了
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
// 开始休眠,等待被唤醒
__CFRunLoopSetSleeping(rl);
__CFPortSetInsert(dispatchPort, waitSet);
do {
// 循环在做一件事情,等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
} while (1);
// 醒过来了
__CFPortSetRemove(dispatchPort, waitSet);
__CFRunLoopSetIgnoreWakeUps(rl);
__CFRunLoopUnsetSleeping(rl);
// 通知Observers,已经醒过来了
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
// goto 跳转过来了
// 判断一下是被谁叫醒的
handle_msg:;
// 被Timer唤醒 -- __CFRunLoopDoTimers
if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
CFRUNLOOP_WAKEUP_FOR_TIMER();
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer, because we apparently fired early
__CFArmNextTimerInMode(rlm, rl);
}
}
// 被Timer唤醒 -- __CFRunLoopDoTimers
else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
CFRUNLOOP_WAKEUP_FOR_TIMER();
// 处理Timer
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer
__CFArmNextTimerInMode(rlm, rl);
}
}
// 被 GCD 唤醒
else if (livePort == dispatchPort) {
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
sourceHandledThisLoop = true;
didDispatchPortLastTime = true;
} else {
CFRUNLOOP_WAKEUP_FOR_SOURCE();
// 处理source1
sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
// 看下有没有block需要处理
__CFRunLoopDoBlocks(rl, rlm);
// 根据上面的处理结果,看下接下来是退出还是继续 do while循环
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); // 条件满足继续循环
if (timeout_timer) {
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
} else {
free(timeout_context);
}
return retVal;
}
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
// 通知Observer进入RunLoop
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
// 核心RunLoop逻辑
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
// 通知Observer RunLoop结束循环
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
return result;
}
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
- 01、通知Observers:进入RunLoop
- 02、通知Observers:将要处理Timers
- 03、通知Observers:将要处理Sources
- 04、处理Blocks
- 05、处理Source0(可能会再次处理Blocks)
- 06、如果存在Source1,就跳转到第8步
- 07、通知Observers:开始休眠(等待消息唤醒)
- 08、通知Observers:结束休眠(被某个消息唤醒)
- 01> 处理Timer
- 02> 处理GCD Async To Main Queue
- 03> 处理Source1
- 09、处理Blocks
- 10、根据前面的执行结果,决定如何操作
- 01> 回到第02步
- 02> 退出Loop
- 11、通知Observers:退出Loop
流程图如下:
image.png
GCD其他的时候是不依赖RunLoop的,只有一种情况会让RunLoop去干活
从其他的线程回到主线程的时候会通过RunLoop
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"*****%@",[NSThread currentThread]);
});
});
image.png