美文网首页
探寻RunLoop

探寻RunLoop

作者: SK_Wang | 来源:发表于2020-07-10 11:44 被阅读0次

    顾名思义,RunLoop就是运行循环,在程序运行过程中循环做一些事情。
    应用的一些场景:

    • 定时器(Timer)、PerformSelector
    • GCD Async Main Queue
    • 事件响应、手势识别、界面刷新
    • 网络请求
    • AutoreleasePool
    • 控制线程生命周期(线程保活)
    • 监控应用卡顿
    • 性能优化

    iOS中有2套API来访问和使用RunLoop

    • Foundation:NSRunLoop
    • Core Foundation:CFRunLoopRef

    NSRunLoop和CFRunLoopRef都代表着RunLoop对象,NSRunLoop是基于CFRunLoopRef的一层OC包装,CFRunLoopRef是开源的https://opensource.apple.com/tarballs/CF/

    RunLoop与线程

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

    RunLoop相关的类

    Core Foundation中关于RunLoop的5个类

    • CFRunLoopRef
    • CFRunLoopModeRef
    • CFRunLoopSourceRef
    • CFRunLoopTimerRef
    • CFRunLoopObserverRef
    typedef struct __CFRunLoopMode *CFRunLoopModeRef;
    
    struct __CFRunLoopMode {
        CFRuntimeBase _base;
        CFStringRef _name;
        CFMutableSetRef _sources0;
        CFMutableSetRef _sources1;
        CFMutableArrayRef _observers;
        CFMutableArrayRef _timers;
    };
    
    struct __CFRunLoop {
        pthread_t _pthread;
        CFMutableSetRef _commonModes;
        CFMutableSetRef _commonModeItems;
        CFRunLoopModeRef _currentMode;
        CFMutableSetRef _modes;
    };
    
    

    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会立马退出

    常见的2种Mode

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

    CFRunLoopObserverRef

    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry = (1UL << 0),
        kCFRunLoopBeforeTimers = (1UL << 1),
        kCFRunLoopBeforeSources = (1UL << 2),
        kCFRunLoopBeforeWaiting = (1UL << 5),
        kCFRunLoopAfterWaiting = (1UL << 6),
        kCFRunLoopExit = (1UL << 7),
        kCFRunLoopAllActivities = 0x0FFFFFFFU
    };
    

    可以添加Observer监听RunLoop的所有状态

    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            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;
                case kCFRunLoopAllActivities:
                    NSLog(@"kCFRunLoopAllActivities");
                    break;
            }
            
        });
        CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
        CFRelease(observer);
    

    RunLoop的运行逻辑

    1. 通知Observers:进入Loop
    2. 通知Observers:即将处理Timers
    3. 通知Observers:即将处理Sources
    4. 处理Blocks
    5. 处理Source0(可能会再次处理Blocks)
    6. 如果存在Source1,就跳转到第8步
    7. 通知Observers:开始休眠(等待消息唤醒)
    8. 通知Observers:结束休眠(被某个消息唤醒)
      • 处理Timer
      • 处理GCD Async To Main Queue
      • 处理Source1
    9. 处理Blocks
    10. 根据前面的执行结果,决定如何操作
      • 回到第02步
      • 退出Loop
    11. 通知Observers:退出Loop

    RunLoop休眠的实现原理

    image.png

    相关文章

      网友评论

          本文标题:探寻RunLoop

          本文链接:https://www.haomeiwen.com/subject/hgztcktx.html