__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的声明周期函数ViewDidLoad
、viewWillAppear
……
2. 类似UICollectionViewDataSource的回调方法等-
- 处理唤醒时收到的消息,
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 |