RunLoop -4⃣️- __CFRunLoopRun

__CFRunLoopRun是内部私有方法,只在CFRunLoopRunSpecific中一处调用

  • 方法声明
/**
* @param CFRunLoopRef : rl
* @param CFRunLoopModeRef : rlm
* @param CFTimeInterval : seconds
* @param Boolean: stopAfterHandle
* @param CFRunLoopModeRef : previousMode
*/
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) 
  • 返回值类型
/* Reasons for CFRunLoopRunInMode() to Return */
typedef CF_ENUM(SInt32, CFRunLoopRunResult) {
    kCFRunLoopRunFinished = 1,
    kCFRunLoopRunStopped = 2,
    kCFRunLoopRunTimedOut = 3,
    kCFRunLoopRunHandledSource = 4
};

kCFRunLoopRunFinished 和 kCFRunLoopRunStopped 会终止循环。


分段解析

  • 1、输入参数检查,Stoped直接返回
   // runloop 的状态是否是Stopped
    if (__CFRunLoopIsStopped(rl))
    {
        __CFRunLoopUnsetStopped(rl);
        return kCFRunLoopRunStopped;
    }
   // runloopMode 的状态是否是Stopped
    else if (rlm->_stopped)
    {
        rlm->_stopped = false;
        return kCFRunLoopRunStopped;
    }
  • 2、 GCD 队列的端口设置

if ( 队列安全libdispatchQSafe && isMainRunloop && CurrentRunLoopMode在 _commonModes 的set集合中 ) { dispatchPort 设置为 主线程 runloop 所关联的的通信端口}

    mach_port_name_t dispatchPort = MACH_PORT_NULL;
    Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
    if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name))
        dispatchPort = _dispatch_get_main_queue_port_4CF();
  • 3、超时时长操作: 使用的是GCD的Timer。
    dispatch_source_t timeout_timer = NULL;
    struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
    if (seconds <= 0.0)
    { // instant timeout
        seconds = 0.0;
        timeout_context->termTSR = 0ULL;
    }
    else if (seconds <= TIMER_INTERVAL_LIMIT)
    {
        dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
        timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_retain(timeout_timer);
        timeout_context->ds = timeout_timer;
        timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
        timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
        dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
        dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
        dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
        uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
        dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
        dispatch_resume(timeout_timer);
    }
    else
    { // infinite timeout
        seconds = 9999999999.0;
        timeout_context->termTSR = UINT64_MAX;
    }
  • 4、进入 do - while 循环,直到 reVal 不为 0 。
  // 伪代码,转自·孙源@sunnyxx·的PPT
    SetupThisRunLoopRunTimeoutTimer(); // by GCD timer
    do {
        __CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
        __CFRunLoopDoObservers(kCFRunLoopBeforeSources);
        
        __CFRunLoopDoBlocks();
        __CFRunLoopDoSource0();
        
        CheckIfExistMessagesInMainDispatchQueue(); // GCD
        
        __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);
        var wakeUpPort = SleepAndWaitForWakingUpPorts();
        // mach_msg_trap
        // Zzz...
        // Received mach_msg, wake up
        __CFRunLoopDoObservers(kCFRunLoopAfterWaiting);
        // Handle msgs
        if (wakeUpPort == timerPort) {
            __CFRunLoopDoTimers();
        } else if (wakeUpPort == mainDispatchQueuePort) { // GCD
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
        } else {
            __CFRunLoopDoSource1();
        }
       __CFRunLoopDoBlocks();
   } while (!stop && !timeout);
do - while.png
  • __CFRunLoopDoBlocks
    处理的回调Blocks包括:
    1. VC的声明周期函数ViewDidLoadviewWillAppear ……
    2. 类似UICollectionViewDataSource的回调方法等

    1. 处理唤醒时收到的消息,Handler msgs
   // Handler msgs  
   if(wakeUpPort == timerPort){  
       //如果是timer唤醒就去执行timer  
       __CFRunLoopDoTimer();  
   }else if(wakeUpPort == mainDispatchQueuePort){  
       //GCD需要我,就去调GCD的事件  
       __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE();  
   }else{  
       //比如说网络来数据了就会用这个端口唤醒,然后做数据处理  
       __CFRunloopDoSource1();  
   }  
Handler msgs
处理timer
执行GCD丢进MainThread的Blocks
处理Source1

你可能感兴趣的:(RunLoop -4⃣️- __CFRunLoopRun)