美文网首页
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

相关文章

  • iOS RunLoop 相关面试题

    RunLoop监听 Runloop运行逻辑

  • NSRunLoop

    RunLoop运行逻辑 RunLoop面试题: 1、什么是RunLoop? 答:从字面意思上:运行循环、跑圈。 其...

  • RunLoop -- 运行逻辑

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

  • Runloop源码解析:运行逻辑

    Runloop应用: Timer失效问题; 线程保活; Runloop的运行逻辑: 入口函数 通知Observer...

  • iOS Runloop底层详解

    一 什么是Runloop 二 Runloop的运行逻辑 三 Runloop在实际开发中的应用 一 什么是Runlo...

  • 2. runloop 事件处理

    Runloop处理事件模型 RunLoop 的运行逻辑 01、通知Observers:进入Loop 02、通知Ob...

  • RunLoop(二)

    RunLoop的运行逻辑 本文Demo代码可见gitHub_Demo 查看源码: RunLoop休眠的实现原理(如...

  • 12.runloop问题

    问题 1.个人对runloop的理解2.runloop 运行逻辑3.监听runloop 的模式4.获取当前子线程中...

  • 三十五、Runloop之(四)Runloop的运行逻辑

    Runloop的运行逻辑 CFRunloopObserver的创建及监听 监听CFRunloopModeRef的切...

  • runloop和线程的关系

    runLoop是运行循环,处理app中的事件,保持程序的持续运行 内部运行逻辑:1.通知Observers进入lo...

网友评论

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

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