iOS高级进阶

Runloop源码解析:运行逻辑

2019-11-12  本文已影响0人  南城同學

Runloop应用:


Runloop的运行逻辑:

入口函数

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)
  1. 通知Observers:进入Loop;
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
  1. 通知Observers:即将处理Timers;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
  1. 通知Observers:即将处理Sources;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
  1. 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);
  1. 处理Source0(可能会再次处理Blocks);
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        if (sourceHandledThisLoop) {
            __CFRunLoopDoBlocks(rl, rlm);
    }
  1. 如果存在Source1,就跳转到第8步;
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
                goto handle_msg;
            }
  1. 通知Observers:开始休眠(等待消息唤醒);
//通知Observers:即将休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);

//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
            
  1. 通知Observers:结束休眠(被某个消息唤醒):
//通知Observers:结束休眠
 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);

  1. 处理Timer;
  2. 处理GCD Async To Main Queue;
  3. 处理Source1;
if(被timer唤醒) {
//处理Timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
} else if (被GCD唤醒) {
//处理CGD
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);

} else { //被Source1唤醒
//处理Source1
 __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
}

  1. 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);

  1. 根据前面的执行结果,决定如何操作:
    1. 回到第02步;
    2. 或 退出Loop;
 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);
  1. 通知Observers:退出Loop.
 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

扩展:Runloop休眠实现的原理:

//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);

线程阻塞有两种方式:

  1. 代码阻塞,但是当前线程并没有休息;
while(1);
  1. 真的让当前线程去“休息”。
上一篇 下一篇

猜你喜欢

热点阅读