iOS底层原理(三):RunLoop

2020-09-03  本文已影响0人  冰风v落叶
一、什么是RunLoop?
没有RunLoop的话 有了RunLoop
void CFRunLoopRun(void) { /* DOES CALLOUT */
  int32_t result;
  do {
    result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(),kCFRunLoopDefaultMode, 1.0e10, false);
    CHECK_FOR_FORK();
  } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
二、RunLoop对象
/// 全局的Dictionary,key 是 pthread_t, value 是 CFRunLoopRef
static CFMutableDictionaryRef loopsDic;
/// 访问 loopsDic 时的锁
static CFSpinLock_t loopsLock;

/// 获取一个 pthread 对应的 RunLoop。
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {
OSSpinLockLock(&loopsLock);

if (!loopsDic) {
// 第一次进入时,初始化全局Dic,并先为主线程创建一个 RunLoop。
loopsDic = CFDictionaryCreateMutable();
CFRunLoopRef mainLoop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);
}

/// 直接从 Dictionary 里获取。
CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread));

if (!loop) {
/// 取不到时,创建一个
loop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, thread, loop);
/// 注册一个回调,当线程销毁时,顺便也销毁其对应的 RunLoop。
_CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);
}

OSSpinLockUnLock(&loopsLock);
return loop;
}

CFRunLoopRef CFRunLoopGetMain() {
return _CFRunLoopGet(pthread_main_thread_np());
}

CFRunLoopRef CFRunLoopGetCurrent() {
return _CFRunLoopGet(pthread_self());
}

[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象
三、RunLoop对外的接口

下面我们就详细说说关于RunLoop的五个类

创建RunLoop时,系统默认注册了五种mode:

- (1). ```kCFRunLoopDefaultMode```: 默认 mode,通常主线程在这个 mode 下运行

- (2). ```UITrackingRunLoopMode```: 追踪mode,保证Scrollview滑动顺畅不受其他 mode 影响

- (3). ```UIInitializationRunLoopMode```: 启动程序后的过渡mode,启动完成后就不再使用

- (4). ```GSEventReceiveRunLoopMode```: Graphic相关事件的mode,通常用不到

- (5). ```kCFRunLoopCommonModes```: 占位用的mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
  kCFRunLoopEntry = (1UL << 0), // 即将进入Loop
  kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer
  kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
  kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
  kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
  kCFRunLoopExit = (1UL << 7), // 即将退出Loop
};
image.png
四、RunLoop的运行逻辑
image.png image.png
五、RunLoop的应用
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
          [[NSThread currentThread] setName:@"AFNetworking"];
          NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
          [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
          [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });
    return _networkRequestThread;
}
image.png
六、面试题
上一篇 下一篇

猜你喜欢

热点阅读