likes
comments
collection
share

iOS底层原理探索-----Runloop

作者站长头像
站长
· 阅读数 27

简述

Runloop是一个事件处理循环,属于线程相关基础架构的一部分。它用来安排工作,并协调接收传入的事件。

Runloop是一个do..while循环,和普通循环的区别,在有工作的时候让线程保持忙碌,没有工作时让线程休眠。

Runloop作用:

  • 保持程序的持续运行;

  • 处理App中的各种事件(触摸、定时器、performSelector);

  • 节省CPU资源,该做事就做事,该休息就休息。

Runloop 循环

Runloop在底层的封装为CFRunloop,代码如下:

void CFRunLoopRun(void) {
    /* DOES CALLOUT */ int32_t result; 
    do { 
        // 1.0e10 : 科学计数 1*10^10 
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK(); 
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); 
}

与线程的关系

获取Runloop的两种方式:

// 主运行循环 
CFRunLoopRef mainRunloop = CFRunLoopGetMain(); 

// 当前运行循环 
CFRunLoopRef currentRunloop = CFRunLoopGetCurrent();

主运行循环

进入CFRunLoopGetMain函数:

CFRunLoopRef CFRunLoopGetMain(void) { 
    CHECK_FOR_FORK(); 
    static CFRunLoopRef __main = NULL;     // no retain needed 
    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np());    // no CAS needed 
    return __main; 
}
  • 调用_CFRunLoopGet0函数,通过主线程查找。

当前运行循环

进入CFRunLoopGetCurrent函数:

CFRunLoopRef CFRunLoopGetCurrent(void) { 
    CHECK_FOR_FORK(); 
    //优先TSD中查找 
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl; 
    
    //通过当前线程查找 
    return _CFRunLoopGet0(pthread_self());
}
  • 优先TSD中查找;

  • 调用_CFRunLoopGet0函数,通过当前线程查找。

_CFRunLoopGet0

进入_CFRunLoopGet0函数:

CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) { 
    if (pthread_equal(t, kNilPthreadT)) { 
        //不存在,默认为主线程 
        t = pthread_main_thread_np(); 
    } 
    
    __CFSpinLock(&loopsLock); 
    if (!__CFRunLoops) { 
        __CFSpinUnlock(&loopsLock); 
        
        //创建全局字典,标记为kCFAllocatorSystemDefault 
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); 
        
        //通过主线程 创建主运行循环 
        CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np()); 
        
        // dict : key value 
        //利用dict,进行key-value绑定操作,线程和Runloop是一一对应的 
        CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop); 
        
        if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { 
            CFRelease(dict);
        } 
        
        CFRelease(mainLoop); 
        __CFSpinLock(&loopsLock); 
    }
    
    //通过其他线程获取Runloop 
    
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); 
    __CFSpinUnlock(&loopsLock);
    if (!loop) { 
        //如果没有获取到,创建一个Runloop 
        CFRunLoopRef newLoop = __CFRunLoopCreate(t); 
        __CFSpinLock(&loopsLock); 
        loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); 
        if (!loop) { 
            //与线程进行key-value绑定 
            CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); loop = newLoop; 
        } 
        
        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it 
        __CFSpinUnlock(&loopsLock); 
        CFRelease(newLoop); 
    }
    
    if (pthread_equal(t, pthread_self())) { 
        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL); 
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) { 
            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
        } 
    } 
    
    return loop; 
}
  • Runloop与线程一一对应;

  • RunLoop对象在第一次获取RunLoop时创建,销毁则是在线程结束的时候;

  • 主线程的RunLoop对象由系统自动创建,而子线程的RunLoop对象需要开发者主动创建;

  • RunLoop并不保证线程安全;

  • 当前线程内部不能操作其他线程的RunLoop对象。

结构

进入__CFRunLoopCreate函数:

static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
    CFRunLoopRef loop = NULL; 
    CFRunLoopModeRef rlm; 
    uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase); 
    loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL); 
    if (NULL == loop) { 
        return NULL;
    } 
    
    (void)__CFRunLoopPushPerRunData(loop);
    __CFRunLoopLockInit(&loop->_lock); 
    loop->_wakeUpPort = __CFPortAllocate(); 
    
    if (CFPORT_NULL == loop->_wakeUpPort) HALT; 
    __CFRunLoopSetIgnoreWakeUps(loop); 
    loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); 
    CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode); 
    loop->_commonModeItems = NULL; 
    loop->_currentMode = NULL; 
    loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); 
    loop->_blocks_head = NULL; 
    loop->_blocks_tail = NULL; 
    loop->_counterpart = NULL; 
    loop->_pthread = t; 
    
#if DEPLOYMENT_TARGET_WINDOWS
    loop->_winthread = GetCurrentThreadId(); 
#else 
    loop->_winthread = 0;
#endif
    rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
    if (NULL != rlm) __CFRunLoopModeUnlock(rlm); 
    return loop; 
}
  • 创建RunLoop,返回CFRunLoopRef类型。 找到CFRunLoopRef的定义:
typedef struct __CFRunLoop * CFRunLoopRef;
  • RunLoop也是一个对象,本质是__CFRunLoop结构体类型的指针。

找到__CFRunLoop结构体的定义:

struct __CFRunLoop { 
    CFRuntimeBase _base; 
    pthread_mutex_t _lock;     /* locked for accessing mode list */
    __CFPort _wakeUpPort;     // used for CFRunLoopWakeUp
    Boolean _unused; 
    volatile _per_run_data *_perRunData;     // reset for runs of the run loop 
    pthread_t _pthread;
    uint32_t _winthread; 
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes; 
    struct _block_item *_blocks_head; 
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};
  • _commonModes_commonModeItems都是集合类型,表示在Runloop中可能会对应多个。

Modes

获取Runloop下的所有Modes

CFRunLoopRef lp = CFRunLoopGetCurrent(); 
CFArrayRef modeArray= CFRunLoopCopyAllModes(lp);
NSLog(@"modeArray == %@",modeArray); 

打印输出结果:

modeArray == ( 
    UITrackingRunLoopMode, 
    GSEventReceiveRunLoopMode, 
    kCFRunLoopDefaultMode 
    )
  • 一个RunLoop对应多个Modes

创建一个NSTimer,将其加入Runloop并运行:

NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { 
    NSLog(@"fire in home -- %@",[[NSRunLoop currentRunLoop] currentMode]); 
}]; 

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  • 添加到RunLoop中,必须指定Mode,这证明Timer的运行依赖于RunLoopMode

然后再次获取当前Runloop正在运行的Mode

CFRunLoopRef lp = CFRunLoopGetCurrent(); 
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(lp);
NSLog(@"mode == %@",mode);

打印输出结果:

mode == kCFRunLoopDefaultMode

Mode类型:

  • NSDefaultRunLoopMode:默认的Mode,正常情况下都在该Mode下;

  • NSConnectionReplyMode:将此模式与NSConnection对象结合使用来监视回复;

  • NSModalPanelRunLoopMode:使用这种模式来识别用于模态面板的事件;

  • NSEventTrackingRunLoopMode:使用该Mode跟踪来自用户交互的事件,例如:UITableView上下滑动;

  • NSRunLoopCommonModes:伪模式,该集合默认包括默认、模态和事件跟踪模式。

在官方文档中,共提及以上五种Mode类型。而iOS中,只公开暴露了NSDefaultRunLoopModeNSRunLoopCommonModes两种。

NSRunLoopCommonModes是伪模式,本质是Mode的集合,包含NSDefaultRunLoopModeNSModalPanelRunLoopModeNSEventTrackingRunLoopMode

Mode主要是用于指定RunLoop中事件优先级。

Items

除了Timer之外,我们还可以指定其他事务指定它在CFRunLoopDefaultMode下执行,所有一个Mode对应多个Items

SourceTimerObserver统称Item

Runloop可处理以下事务类型:

  • Block应用:__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__; 如图: iOS底层原理探索-----Runloop

  • 调用timer__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__; 如图: iOS底层原理探索-----Runloop

  • 响应source0__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__; 如图: iOS底层原理探索-----Runloop

  • 响应source1__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__

  • GCD主队列:__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__; 如图: iOS底层原理探索-----Runloop

  • observer源:__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__。 如代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotNotification:) name:@"helloMyNotification" object:nil];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    [[NSNotificationCenter defaultCenter] postNotificationName:@"helloMyNotification" object:@"cooci"];
}

- (void)gotNotification:(NSNotification *)noti{

    // __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
    NSLog(@"gotNotification = %@",noti);
}

Source

Source表示可以唤醒RunLoop的一些事件,例如:用户点击屏幕,就会创建一个RunLoop,主要分为Source0Source1

  • Source0:表示非系统事件,即用户自定义的事件;

  • Source1:表示系统事件,主要负责底层的通讯,具备唤醒能力。

Timer

常用NSTimer定时器。

Observer

Observer主要用于监听RunLoop的状态变化,并作出一定响应。

源码中Observer的定义:

/* Run Loop Observer Activities */ 
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { 
    //进入 
    kCFRunLoopEntry = (1UL << 0), 
    //即将处理Timers 
    kCFRunLoopBeforeTimers = (1UL << 1), 
    //即将处理Sources 
    kCFRunLoopBeforeSources = (1UL << 2), 
    //进入休眠 
    kCFRunLoopBeforeWaiting = (1UL << 5), 
    //被唤醒 
    kCFRunLoopAfterWaiting = (1UL << 6), 
    //退出 
    kCFRunLoopExit = (1UL << 7), 
    kCFRunLoopAllActivities = 0x0FFFFFFFU 
};

Runloop结构图

线程与RunLoop一对一:

iOS底层原理探索-----Runloop

一个RunLoop对应多个Modes,一个Mode对应多个Items

iOS底层原理探索-----Runloop

SourceTimerObserver统称Item

iOS底层原理探索-----Runloop

事务处理

Timer示例

创建CFRunLoopTimer,将其加入到Runloop并执行:

- (void)cfTimerDemo { 
    CFRunLoopTimerContext context = {
        0,
        ((__bridge void *)self),
        NULL, 
        NULL,
        NULL 
    }; 
    
    CFRunLoopRef rlp = CFRunLoopGetCurrent(); 
    /** 
        参数一:用于分配对象的内存 
        参数二:在什么是触发 (距离现在) 
        参数三:每隔多少时间触发一次 
        参数四:未来参数 
        参数五:CFRunLoopObserver的优先级 当在Runloop同一运行阶段中有多个CFRunLoopObserver 正常情况下使用0 
        参数六:回调,比如触发事件,我就会来到这里 
        参数七:上下文记录信息 
     */ 
     CFRunLoopTimerRef timerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 1, 0, 0, lgRunLoopTimerCallBack, &context); 
     CFRunLoopAddTimer(rlp, timerRef, kCFRunLoopDefaultMode);
 } 
 
void lgRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info){
     NSLog(@"%@---%@",timer,info); 
}

进入CFRunLoopAddTimer函数:

void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { 
    CHECK_FOR_FORK(); 
    if (__CFRunLoopIsDeallocating(rl)) return; 
    
    if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; 
    
    __CFRunLoopLock(rl); 
    
    //匹配kCFRunLoopCommonModes,伪模式,集合类型 
    if (modeName == kCFRunLoopCommonModes) { 
        //获取集合
        CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
        
        //获取RunLoop下的事务 
        if (NULL == rl->_commonModeItems) {
            //为空需要重新创建 
            rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
        } 
        
        //将传入的CFRunLoopTimer参数,加入到Items 
        CFSetAddValue(rl->_commonModeItems, rlt); 
        
        //集合不为空 
        if (NULL != set) { 
            CFTypeRef context[2] = {rl, rlt};     
            /* add new item to all common-modes */ 
            //设置回调函数,添加到common-modes中
            CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); CFRelease(set);
        } 
    } else {
        //如果是其他类型,通过名字寻址Mode 
        CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true); 
        if (NULL != rlm) {
            if (NULL == rlm->_timers) { 
                CFArrayCallBacks cb = kCFTypeArrayCallBacks; 
                cb.equal = NULL; 
                rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb); 
            } 
        } 
        
        if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) { 
            __CFRunLoopTimerLock(rlt); 
            if (NULL == rlt->_runLoop) { 
                rlt->_runLoop = rl;
            } else if (rl != rlt->_runLoop) { 
                __CFRunLoopTimerUnlock(rlt); 
                __CFRunLoopModeUnlock(rlm);
                __CFRunLoopUnlock(rl);
                return;
            } 
            
            //如果匹配,将Runloop加进去,执行依赖于runloop run 
            CFSetAddValue(rlt->_rlModes, rlm->_name); 
            __CFRunLoopTimerUnlock(rlt);
            __CFRunLoopTimerFireTSRLock(); 
            __CFRepositionTimerInMode(rlm, rlt, false); 
            __CFRunLoopTimerFireTSRUnlock(); 
            
            if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
                // Normally we don't do this on behalf of clients, but for 
                // backwards compatibility due to the change in timer handling... 
                if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
                
            } 
        } 
        
        if (NULL != rlm) {
            __CFRunLoopModeUnlock(rlm); 
        }
    } 
    
    __CFRunLoopUnlock(rl); 
}

CFRunLoopAddTimer源码中,没有找到执行事务的函数:

iOS底层原理探索-----Runloop

  • 所以,真正事务的执行,依赖于runloop run

__CFRunLoopRun

进入CFRunLoopRun函数:

void CFRunLoopRun(void) { 
    /* DOES CALLOUT */ 
    int32_t result;
    do { 
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); 
        CHECK_FOR_FORK(); 
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); 
}
  • 通过CFRunLoopRunSpecific函数,得到result结果;

  • 1.0e10:科学计数法,1 * 10 ^ 10

进入CFRunLoopRunSpecific函数:

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);
    
    //如果没找到 || mode中没有注册任何事件,则就此停止,不进入循环 
    if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) { 
        Boolean did = false;
        if (currentMode) __CFRunLoopModeUnlock(currentMode); 
        __CFRunLoopUnlock(rl); 
        return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished; 
    } 
    
    volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl); 
    //取上一次运行的mode 
    CFRunLoopModeRef previousMode = rl->_currentMode; 
    
    //如果本次mode和上次的mode一致
    rl->_currentMode = currentMode; 
    
    //初始化一个result为kCFRunLoopRunFinished 
    int32_t result = kCFRunLoopRunFinished; 
    
    if (currentMode->_observerMask & kCFRunLoopEntry )
    /// 1. 通知 Observers: RunLoop 即将进入 loop。 
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
    if (currentMode->_observerMask & kCFRunLoopExit ) 
    /// 10. 通知 Observers: RunLoop 即将退出。
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); 
    
    __CFRunLoopModeUnlock(currentMode); 
    __CFRunLoopPopPerRunData(rl, previousPerRun);
    rl->_currentMode = previousMode;
    __CFRunLoopUnlock(rl);
    return result; 
}
  • 在进入和退出之间,调用__CFRunLoopRun函数。

进入__CFRunLoopRun函数:

iOS底层原理探索-----Runloop

  • 每一种类型都有特定的处理函数调用。

__CFRunLoopDoTimer

进入__CFRunLoopDoTimers函数:

static Boolean __CFRunLoopDoTimers(CFRunLoopRef rl, CFRunLoopModeRef rlm, uint64_t limitTSR) { 
    /* DOES CALLOUT */ 
    Boolean timerHandled = false;
    CFMutableArrayRef timers = NULL;
    
    //程序中正在运行的timer可能不止一个 
    for (CFIndex idx = 0, cnt = rlm->_timers ? CFArrayGetCount(rlm->_timers) : 0; idx < cnt; idx++) { 
        //遍历timer,从Mode中获取
        CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); 
        if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
            if (rlt->_fireTSR <= limitTSR) {
                if (!timers) timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 
                CFArrayAppendValue(timers, rlt); 
            } 
         } 
     } 
     
     for (CFIndex idx = 0, cnt = timers ? CFArrayGetCount(timers) : 0; idx < cnt; idx++) { 
         CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timers, idx); 
         
         //执行timer 
         Boolean did = __CFRunLoopDoTimer(rl, rlm, rlt); 
         timerHandled = timerHandled || did; 
     } 
     
     if (timers) CFRelease(timers); 
     return timerHandled; 
}

进入__CFRunLoopDoTimer函数:

iOS底层原理探索-----Runloop

  • timer的回调。

处理流程

  • 通过CFRunLoopAddTimertimer加入到指定Mode中;

  • 事务的执行依赖于runloop run

    • 调用CFRunLoopRunCFRunLoopRunSpecific函数,在Runloop进入和离开之间,调用__CFRunLoopRun函数。
  • __CFRunLoopRun中,包含对ObserversSource0Source1Timer的逻辑处理:

    • 针对timer的处理,调用__CFRunLoopDoTimers,遍历当前正在运行的timer

    • 针对单个timer,调用__CFRunLoopDoTimer函数,执行事务的处理。

Runloop事务处理的流程图:

iOS底层原理探索-----Runloop

底层原理

CFRunLoopRunSpecific中的核心代码:

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; 
}

__CFRunLoopRun中的核心代码:

static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { 
    int32_t retVal = 0;
    do { 
        // itmes 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; 
}

流程图:

iOS底层原理探索-----Runloop

转载自:https://juejin.cn/post/7008081207896309768
评论
请登录