RunLoop部分

--------------------RunLoop--------------------

什么是RunLoop

运行循环,在程序运行过程中循环做一些事情

RunLoopde 应用范畴

定时器(Timer)、PerformSelector
GCD Async Main Queue
事件响应、手势识别、界面刷新
网络请求
AutoreleasePool

RunLoop与线程

  1. 每条线程都有唯一的一个与之对应的RunLoop对象
  2. RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value
  3. 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
  4. RunLoop会在线程结束时销毁
  5. 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

获得RunLoop对象

Foundation
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

Core Foundation
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象

RunLoop相关的5个类:
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef

CFRunLoop和 CFRunLoopMode

// CFRunLoop.h
typedef struct __CFRunLoop * CFRunLoopRef;
// CFRunLoop.c
struct __CFRunLoop {
    pthread_t _pthread;  // 与线程一一对应
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    ...
};
// CFRunLoop.h
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
// CFRunLoop.c
struct __CFRunLoopMode {
    CFStringRef _name;             // mode 类型,如:NSDefaultRunLoopMode
    CFMutableSetRef _sources0;     // CFRunLoopSourceRef
    CFMutableSetRef _sources1;     // CFRunLoopSourceRef
    CFMutableArrayRef _observers;  // CFRunLoopObserverRef
    CFMutableArrayRef _timers;     // CFRunLoopTimerRef
    ...
};

CFRunLoopModeRef

  • CFRunLoopModeRef代表RunLoop的运行模式
  • 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer
  • RunLoop启动时只能选择其中一个Mode,作为currentMode
  • 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入
    不同组的Source0/Source1/Timer/Observer能分隔开来,互不影响
  • 如果Mode里没有任何Source0/Source1/Timer/Observer,RunLoop会立马退出

常见的两种mode:

  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

CFRunLoopObserverRef

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),          // 即将进入 RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1),   // 即将处理 Timers
    kCFRunLoopBeforeSources = (1UL << 2),  // 即将处理 Sources
    kCFRunLoopBeforeWaiting = (1UL << 5),  // 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),   // 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7),           // 即将退出 RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU  // 表示以上所有状态
};

添加RunLoop的监听:

// 创建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    switch (activity) {
        case kCFRunLoopEntry: {
            NSLog(@"kCFRunLoopEntry");
            break;
        }
        case kCFRunLoopBeforeTimers: {
            NSLog(@"kCFRunLoopEntry");
        } break;
        case kCFRunLoopBeforeSources: {
            NSLog(@"kCFRunLoopEntry");
        } break;
        case kCFRunLoopBeforeWaiting: {
            NSLog(@"kCFRunLoopEntry");
        } break;
        case kCFRunLoopAfterWaiting: {
            NSLog(@"kCFRunLoopEntry");
        } break;
        case kCFRunLoopExit: {
            NSLog(@"kCFRunLoopExit");
            break;
        }
        default:
            break;
    }
});
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
// 释放
CFRelease(observer);

RunLoop的运行逻辑

先上一张老图


image.png
  • Source0
    触摸事件处理
    performSelector:onThread:

  • Source1
    基于Port的线程间通信
    系统事件捕捉

  • Timers
    NSTimer
    performSelector:withObject:afterDelay:

  • Observers
    用于监听RunLoop的状态
    UI刷新(BeforeWaiting)
    Autorelease pool(BeforeWaiting)

过程:


image.png

你可能感兴趣的:(RunLoop部分)