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总结的到位点
好文链接
发表评论