美文网首页
RunLoop内部调用过程

RunLoop内部调用过程

作者: SPIREJ | 来源:发表于2019-11-10 15:04 被阅读0次

上一篇:
RunLoop介绍篇
下一篇:
RunLoop应用篇

RunLoop的可执行底层源码已经放在这里了,需要看源码的朋友可自行下载https://github.com/SPIREJ/RunLoop

RunLoop介绍篇 我有讲到runloop运行逻辑图

可以来说下官方文档给我们的RunLoop逻辑。

在每次运行开启RunLoop的时候,所在线程的RunLoop会自动处理之前未处理的事件,并且通知相关的观察者。

具体顺序如下:

  1. 通知观察者RunLoop已经启动
  2. 通知观察者即将要开始的定时器
  3. 通知观察者任何即将要启动的非基于端口的源
  4. 启动任何准备好的非基于端口的源
  5. 如果基于端口的源准备好并处于等待状态,立即启动,并进入步骤9
  6. 通知观察者线程进入休眠状态
  7. 将线程置于休眠直到任一下面的时间发生:
    • 某一事件到达基于端口的源
    • 定时器启动
    • RunLoop设置的时间已经超时
    • RunLoop被显示唤醒
  8. 通知观察者线程即将被唤醒
  9. 处理未处理的事件
    • 如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2
    • 如果输入源启动,传递相应的消息
    • 如果RunLoop被显示唤醒且事件还没超时,重启RunLoop。进入步骤2
  10. 通知观察者RunLoop结束

这里我们可以在runloop的源码里面找到实现逻辑,主要的函数包括CFRunLoopRunSpecific入口函数和做 do...while... 的CFRunLoopRun函数

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
    __CFRunLoopLock(rl);
    
    /// 首先根据modeName找到对应mode
    CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
    
    
    /// 通知 Observers: RunLoop 即将进入 loop。
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
    
    /// 内部函数,进入loop
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
    
    /// 通知 Observers: RunLoop 即将退出。
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
    
    return result;
}

/// 核心函数
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
    
    int32_t retVal = 0;
    do {
        
        /// 通知 Observers: 即将处理timer事件
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
        
        /// 通知 Observers: 即将处理Source事件
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources)
        
        /// 处理Blocks
        __CFRunLoopDoBlocks(rl, rlm);
        
        /// 处理sources0
        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        
        /// 处理sources0返回为YES
        if (sourceHandledThisLoop) {
            /// 处理Blocks
            __CFRunLoopDoBlocks(rl, rlm);
        }
        
        
        /// 判断有无端口消息(Source1)
        if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
            /// 处理消息
            goto handle_msg;
        }
        
        /// 通知 Observers: 即将进入休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        __CFRunLoopSetSleeping(rl);
        
        /// 等待被唤醒
        __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
        
        
        // user callouts now OK again
        __CFRunLoopUnsetSleeping(rl);
        
        /// 通知 Observers: 被唤醒,结束休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
        
    handle_msg:
        if (被Timer唤醒) {
            /// 处理Timers
            __CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
        } else if (被GCD唤醒) {
            /// 处理gcd
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
        } else if (被Source1唤醒) {
            /// 被Source1唤醒,处理Source1
            __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)
        }
        
        /// 处理block
        __CFRunLoopDoBlocks(rl, rlm);
        
        
        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);
    
    return retVal;
}

// main  dispatch queue
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__

// __CFRunLoopDoObservers
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__

// __CFRunLoopDoBlocks
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__

// __CFRunLoopDoSources0
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__

// __CFRunLoopDoSource1
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__

// __CFRunLoopDoTimers
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__

看完这里,应该就能理解runloop的内部调用逻辑实现了。下一篇 runloop应用篇 将举例runloop的应用。

相关文章

  • RunLoop介绍

    RunLoop三篇文章:RunLoop介绍篇RunLoop内部调用过程RunLoop应用篇 本篇包括以下内容: R...

  • RunLoop内部调用过程

    上一篇:RunLoop介绍篇下一篇:RunLoop应用篇 RunLoop的可执行底层源码已经放在这里了,需要看源码...

  • RunLoop应用篇

    基础理论请移步这两篇:RunLoop介绍篇RunLoop内部调用过程 一. runloop下timer,obser...

  • iOS RunLoop内部执行过程

    入口函数: 可以看出来runLoop是do while 循环. 下面我将就源码解释下: RunLoop实现休眠的原...

  • RunLoop

    实际上 RunLoop 内部就是一个 do-while 循环 当你调用 CFRunLoopRun() 时,线程就会...

  • 运行循环&运行时

    实际上RunLoop 就是一个函数,其内部是一个do-while 循环。当你调用CFRunLoopRun() 时,...

  • dailyLearning -- runLoop

    runLoop runLoop 对外的接口及相关类 runLoop 内部逻辑 runLoop 可以做啥 runLo...

  • RunLoop

    RunLoop思考 讲讲RunLoop,项目中实际应用? RunLoop内部实现逻辑以及数据结构? RunLoop...

  • iOS知识复习笔记(4)---RunLoop相关

    一、底层原理和调用过程 Runloop 和线程一一对应,主线程程序启动默认开启runloop ,其他线程默认没有r...

  • 第一篇:RunLoop的一些理论知识

    目录一、什么是RunLoop二、RunLoop和线程的关系三、RunLoop的Mode四、RunLoop的内部逻辑...

网友评论

      本文标题:RunLoop内部调用过程

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