1、获取RunLoop对象

查看 RunLoop源码 CFRunLoop.c中:

  1. CFRunLoopRef CFRunLoopGetCurrent(void) {
  2. CHECK_FOR_FORK();
  3. CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
  4. if (rl) return rl;
  5. return _CFRunLoopGet0(pthread_self());
  6. }
  1. CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
  2. ......
  3. // 读取
  4. CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
  5. if (!loop) {// 没有的话就创建一个
  6. CFRunLoopRef newLoop = __CFRunLoopCreate(t);
  7. __CFLock(&loopsLock);
  8. loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
  9. if (!loop) {
  10. CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
  11. loop = newLoop;
  12. }
  13. }
  14. ......
  15. return loop;
  16. }

通过查看源码可知当,通过CFRunLoopGetCurrent读取当前RunLoop时,如果没有就创建一个新的RunLoop,并保存在CFRunLoops全局字典中,CFRunLoops字典是以线程作为key,RunLoop作为value。

2、RunLoop的结构

查看源码CFRunLoop.c中,RunLoop底层结构如下:

  1. struct __CFRunLoop {
  2. ......
  3. pthread_t _pthread; // 所在线程
  4. CFMutableSetRef _commonModes;
  5. CFMutableSetRef _commonModeItems;
  6. CFRunLoopModeRef _currentMode; // 当前模式
  7. CFMutableSetRef _modes; // 所有模式
  8. ......
  9. };

RunLoopMode底层结构如下:

  1. typedef struct __CFRunLoopMode *CFRunLoopModeRef;
  2. struct __CFRunLoopMode {
  3. ......
  4. CFStringRef _name; // 模式的名字
  5. CFMutableSetRef _sources0;
  6. CFMutableSetRef _sources1;
  7. CFMutableArrayRef _observers;
  8. CFMutableArrayRef _timers;
  9. ......
  10. };

_sources0和_sources1里保存着CFRunLoopSourceRef对象,_observers保存着CFRunLoopObserverRef对象,_timers保存着CFRunLoopTimerRef对象。
RunLoop和Mode的结构关系如下图所示:
image.png

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的影响。