RunLoop的具体流程或者说_source0,_source1,_observer,_timer都干了些什么

source0: 主要负责触摸事件,performSelector等等

source1: 线程间通讯,系统事件捕获(比如屏幕点击等等)

observer: RunLoop的状态变化,和UI刷新(休眠之前),autorelease(休眠之前)

timer: NSTimer里面的操作,延时函数

要想知道流程,首先就得找到源码的入口

import UIKit

class ViewController: UIViewController {

@objc func test()

{

print("1")

}

override func viewDidLoad() {

super.viewDidLoad()

self.perform(Selector("test"), with: nil, afterDelay: 1.0)

// Do any additional setup after loading the view.

}

}

比如新建个项目写个延时函数,然后打断点到test里面,用指令bt输出函数调用栈

frame #4: 0x000000010a55e1c2 CoreFoundation`__CFRunLoopDoTimer + 923

frame #5: 0x000000010a55d781 CoreFoundation`__CFRunLoopDoTimers + 265

frame #6: 0x000000010a557dc0 CoreFoundation`__CFRunLoopRun + 2010

frame #7: 0x000000010a557103 CoreFoundation`CFRunLoopRunSpecific + 567

frame #8: 0x0000000109926cd3 GraphicsServices`GSEventRunModal + 139

frame #9: 0x00000001123f7e63 UIKitCore`-[UIApplication _run] + 928

frame #10: 0x00000001123fca53 UIKitCore`UIApplicationMain +

就会出现这样的顺序,可以发现延时函数确实是归Timer处理,但这不是重点,会走到Run函数,下层还有个RunSpecific,那直接复制粘贴

void CFRunLoopRun(void) { /* DOES CALLOUT */

int32_t result;

do {

result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);

CHECK_FOR_FORK();

} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);

}

 run函数本质只是循环执行CFRunLoopRunSpecific,结束条件是RunLoop自然结束,或者手动停止

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */

CHECK_FOR_FORK();

if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;

__CFRunLoopLock(rl);

CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);

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

CFRunLoopModeRef previousMode = rl->_currentMode;

rl->_currentMode = currentMode;

int32_t result = kCFRunLoopRunFinished;

//开始

if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);

//具体操作

result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);

//结束

if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

__CFRunLoopModeUnlock(currentMode);

__CFRunLoopPopPerRunData(rl, previousPerRun);

rl->_currentMode = previousMode;

__CFRunLoopUnlock(rl);

return result;

}

然后可以看到外部就是检测里面的状态进行操作的,先简单解释下状态

1.做一些常规操作,比如判断是否已经被释放,上锁情况,获取当前模式等等等等

2.调用了__CFRunLoopDoObservers处理了一些基础信息,另外变更RunLoop的状态

3.具体的操作在

static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) 

(这个函数里面,实在是太长了,感兴趣的自行查看目录是CF->CFRunLoop.c的2331行开始,我这只是节选了具体的操作do-while的一部分代码)

int32_t retVal = 0;

do {

//如果有就处理Timer

__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);

//如果有就处理block

__CFRunLoopDoBlocks(rl, rlm);

//如果有就处理Source0

Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);

if (sourceHandledThisLoop) {

//可能还会处理一次block(事件回调)

__CFRunLoopDoBlocks(rl, rlm);

}

//处理source1,的线程问题

if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {

//如果有就跳转到handle_msg,就是处理线程之间的通讯消息

goto handle_msg;

}

//如果处理完了设置状态进入休眠

if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting))

__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);

__CFRunLoopSetSleeping(rl);

//计算休眠时间

CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent();

//等待其它消息来唤醒

__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);

rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart));

// user callouts now OK again 用户唤醒了,现在继续搞起

__CFRunLoopUnsetSleeping(rl); //解除睡眠状态

if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);

//处理消息所以,其实RunLoop重新被唤醒是从处理消息开始的

handle_msg:;

__CFRunLoopSetIgnoreWakeUps(rl);

#if USE_DISPATCH_SOURCE_FOR_TIMERS //如果是被Timer唤醒

else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {

CFRUNLOOP_WAKEUP_FOR_TIMER();

if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {

__CFArmNextTimerInMode(rlm, rl);

}

}

#endif

#if USE_MK_TIMER_TOO. //这里是被Timer唤醒TOO

else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {

CFRUNLOOP_WAKEUP_FOR_TIMER();

if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {

// Re-arm the next timer

__CFArmNextTimerInMode(rlm, rl);

}

}

#endif

else if (livePort == dispatchPort) { //被GCD唤醒

CFRUNLOOP_WAKEUP_FOR_DISPATCH();

__CFRunLoopModeUnlock(rlm);

__CFRunLoopUnlock(rl);

_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);

__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);

_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);

__CFRunLoopLock(rl);

__CFRunLoopModeLock(rlm);

sourceHandledThisLoop = true;

didDispatchPortLastTime = true;

} else {

CFRUNLOOP_WAKEUP_FOR_SOURCE(); //其实懂点英文都看的懂,被Source1唤醒

//处理Source1

CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);

//处理block

__CFRunLoopDoBlocks(rl, rlm);

//设置返回值,是否要终止RunLoop否则重新把循环走一遍再休眠

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

所以可以得到结论,RunLoop的具体操作都是在__RunLoopRun这个函数执行,外层只是负责终止这个RunLoop

4.调用了__CFRunLoopDoObservers处理了即将退出的信息,注意这里只是退出当前这次循环,并不是退出了RunLoop,RunLoop退出必须是各种原因,比如线程终止了,RunLoop里面什么都没有,手动销毁等等情况造成的RunLoop销毁,另外变更RunLoop的状态

 官方图有点晦涩,这点还是MJ总结的到位点 

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: