1、获取RunLoop对象
查看 RunLoop源码 CFRunLoop.c中:
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
......
// 读取
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {// 没有的话就创建一个
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
}
......
return loop;
}
通过查看源码可知当,通过CFRunLoopGetCurrent读取当前RunLoop时,如果没有就创建一个新的RunLoop,并保存在CFRunLoops全局字典中,CFRunLoops字典是以线程作为key,RunLoop作为value。
2、RunLoop的结构
查看源码CFRunLoop.c中,RunLoop底层结构如下:
struct __CFRunLoop {
......
pthread_t _pthread; // 所在线程
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode; // 当前模式
CFMutableSetRef _modes; // 所有模式
......
};
RunLoopMode底层结构如下:
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
......
CFStringRef _name; // 模式的名字
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
......
};
_sources0和_sources1里保存着CFRunLoopSourceRef对象,_observers保存着CFRunLoopObserverRef对象,_timers保存着CFRunLoopTimerRef对象。
RunLoop和Mode的结构关系如下图所示:
3、RunLoopMode
3.1、RunLoopModel特点
CFRunLoopModeRef代表RunLoop的运行模式,一个RunLoop包含若干个Mode,每个Model又包含了若干个Source0、Source1、Observer、Timer。
RunLoop启动时只能选择一个Mode,作为currentMode。如果切换Mode,只能退出当前Loop,再重新选择一个Mode进入。这样可以使不同组的Source0、Source1、Timer、Observer能分隔开来,互不影响。
如果Model里没有任何Source0、Source1、Timer、Observer,RunLoop会马上退出。
3.2、RunLoopMode分类
常见的有2种Mode
kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App默认的Mode,通常主线程是在这个模式下运行。
UITrackingRunLoopModel:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode的影响。