美文网首页
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内部调用过程

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