创建source0:
_rl = [NSRunLoop.currentRunLoop getCFRunLoop];
CFRunLoopSourceContext ctx = {0, NULL, NULL, NULL, NULL, NULL, NULL, sourceSchedule, sourceCancel, sourcePerform};
_source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctx);
CFRunLoopAddSource([NSRunLoop.currentRunLoop getCFRunLoop], _source, kCFRunLoopDefaultMode);
CFRunLoopObserverRef obs = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, observerCallBack, NULL);
CFRunLoopAddObserver([NSRunLoop.currentRunLoop getCFRunLoop], obs, kCFRunLoopDefaultMode);
CFRelease(obs);
[NSRunLoop.currentRunLoop run];
各种回调:
void sourceSchedule(void *info, CFRunLoopRef rl, CFRunLoopMode mode) {
NSLog(@"%s", __func__);
}
void sourceCancel(void *info, CFRunLoopRef rl, CFRunLoopMode mode) {
NSLog(@"%s", __func__);
}
void sourcePerform(void *info) {
NSLog(@"%s", __func__);
}
void observerCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"kCFRunLoopBeforeTimers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"kCFRunLoopBeforeSources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"kCFRunLoopBeforeWaiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"kCFRunLoopAfterWaiting");
break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
}
控制台打印:

给source0发送消息
CFRunLoopSourceSignal(_source);
CFRunLoopWakeUp(_rl);
控制台打印:

总结:
- source0确实是在kCFRunLoopBeforeSources这一步被处理的,与官方文档描述一致。
- 值得注意的是每次执行完source0之后runloop都会退出(kCFRunLoopExit)然后再重新进入(kCFRunLoopEntry)。
- 其实为什么会退出苹果官方文档有讲到:If no input sources or timers are attached to the run loop, this method exits immediately and returns
NO; otherwise, it returns after either the first input source is processed or limitDate is reached.