美文网首页
RunLoop -- 运行逻辑

RunLoop -- 运行逻辑

作者: 踩坑小分队 | 来源:发表于2020-04-11 21:22 被阅读0次

    直接分析下源码
    CFRunLoopRef源码地址
    通过打断点可以从 CFRunLoopRun 方法进行查看

    image.png
    /* 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

    相关文章

      网友评论

          本文标题:RunLoop -- 运行逻辑

          本文链接:https://www.haomeiwen.com/subject/zqksuhtx.html