程序员

RunLoop

2018-06-09  本文已影响17人  MeliodasLy

RunLoop

顾名思义

function loop() {
    initialize();
    do {
        var message = get_next_message();
        process_message(message);
    } while (message != quit);
}

这种模型通常被称作Event Loop
实现这种模型的关键点在于:如何管理事件/消息,如何让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立即被唤醒。

RunLoop实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面的Event Loop的逻辑。线程执行了这个函数后,就会一直处于正常函数内部“接受消息->等待->处理”的循环中,直到这个循环结束(比如传入quit的消息),函数返回。


应用范畴


RunLoop的基本作用


RunLoop对象

    // OC获取当前的RunLoop
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
    // OC获取主线程RunLoop
    NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop];
    // C语言获取当前的RunLoop
    CFRunLoopRef currentRunloop2 = CFRunLoopGetCurrent();
    // C语言获取主线程的RunLoop
    CFRunLoopRef mainRunloop2 = CFRunLoopGetMain();

RunLoop与线程


RunLoop相关的类

CFRunLoopRef

typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
    pthread_t _pthread; // RunLoop所对应的线程
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode; // _modes这个集合里面只有一个模式被称为当前模式_currentMode
    CFMutableSetRef _modes; // 这个集合里面装了很多CFRunLoopModeRef类型的对象
};  

CFRunLoopModeRef

常见的2种Mode
typedef struct __CFRunLoopMode * CFRunLoopModeRef;
struct __CFRunLoopMode {
    CFStringRef _name; // mode的名称
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1; // source里面装了很多CFRunLoopSourceRef类型的对象
    CFMutableArrayRef _observers;// 里面装了很多CFRunLoopObserverRef类型的对象
    CFMutableArrayRef _timers; // 里面装了很多CFRunLoopTimerRef类型的对象
};

CFRunLoopObserverRef

/* RunLoop Observer Activities */
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
    kCFRunLoopAllActivities = 0X0FFFFFFFU
};
// 监听事件的状态变化(只有c语言接口)
// 方法一
void observeRunLoopActivities(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;
    }
}

    // 创建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActivities, NULL);
    // 添加observer到RunLoop中
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    // 释放observer
    CFRelease(observer);
    
// 方法二
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch (activity) {
            case kCFRunLoopEntry: {
                CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopEntry - %@",mode);
                CFRelease(mode);
                break;
            }
            case kCFRunLoopExit:{
                CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
                NSLog(@"kCFRunLoopExit- %@",mode);
                CFRelease(mode);
                break;
            }
                
            default:
                break;
        }
    });
    // 添加observer到RunLoop中
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    // 释放observer
    CFRelease(observer);

根据源码分析,得到如下关系图

runloop

RunLoop的运行逻辑

如下图所示


runloop流程

RunLoop休眠的实现原理

休眠的实现原理

实质:从用户态切换到内核态,去等待消息,没有消息就让线程休眠,不在占用cpu,有消息就唤醒线程。

RunLoop在实际开发中的应用

static int count = 0;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%d",++count);
    }];
// NSDefaultRunLoopMode/UITrackingRunLoopMode才是真正存在的模式    
// NSRunLoopCommonModes并不是一个真的模式,它只是一个标记
// timer能在_commonModes数组中存放的模式下工作
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//    [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
//        NSLog(@"%d",++count);
//    }];
上一篇下一篇

猜你喜欢

热点阅读