RunLoop -- CFRunLoopObserverRef

2020-04-11  本文已影响0人  踩坑小分队

有的时候我们也会自己创建一些Observer去监听RunLoop的状态
RunLoop的状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),           //  即将进入Loop
    kCFRunLoopBeforeTimers = (1UL << 1),    // 即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2),   // 即将处理Sources
    kCFRunLoopBeforeWaiting = (1UL << 5),   // 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),    // 即将休眠结束
    kCFRunLoopExit = (1UL << 7),            // 退出Loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU   // 上面所有的状态
};

接下来,监听一下RunLoop的状态
方法一

// CFRunLoopObserverCallBack 按照这个方法的格式进行创建
void myCFRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    switch (activity) {
        case kCFRunLoopEntry:
            NSLog(@"即将进入Loop");
            break;
        case kCFRunLoopBeforeTimers:
            NSLog(@"即将进入Timers");
        break;
        case kCFRunLoopBeforeSources:
            NSLog(@"即将进入Source");
        break;
        case kCFRunLoopBeforeWaiting:
            NSLog(@"即将进入休眠");
        break;
        case kCFRunLoopAfterWaiting:
            NSLog(@"即将结束休眠");
        break;
        case kCFRunLoopExit:
            NSLog(@"即将退出Loop");
        break;
        default:
            break;
    }
}
/// RunLoop创建RunLoopObserver
    /// @param CFAllocatorRef allocator 指定分配器创建对象,一般写NULL或者kCFAllocatorDefault
    /// @param CFOptionFlags activities 想要监听什么状态,这里监听所有的状态
    /// @param Boolean repeats 是否重复监听
    /// @param CFIndex order 不需要考虑顺序,写0
    /// @param CFRunLoopObserverCallBack callout 按照格式定义一个回调函数
    /// @param CFRunLoopObserverContext *context 传递给监听函数的参数,可以传NULL
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, myCFRunLoopObserverCallBack, NULL);
    
    
    /// RunLoop添加Observer
    /// @param CFRunLoopRef rl 相关监听的RunLoop,这里监听主线程的RunLoop
    /// @param CFRunLoopObserverRef observer 创建的CFRunLoopObserver
    /// @param CFRunLoopMode RunLoop的模式<kCFRunLoopCommonModes包含两种模式>
    
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    
    // C语言创建的对象,最后需要释放
    CFRelease(observer);

CFRunLoopMode

/**
1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode
*/

方法二

/// RunLoop创建RunLoopObserver
    /// @param CFAllocatorRef allocator 指定分配器创建对象,一般写NULL或者kCFAllocatorDefault
    /// @param CFOptionFlags activities 想要监听什么状态,这里监听所有的状态
    /// @param Boolean repeats 是否重复监听
    /// @param CFIndex order 不需要考虑顺序,写0
    /// @param 回调方法
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch (activity) {
               case kCFRunLoopEntry:
                   NSLog(@"即将进入Loop");
                   break;
               case kCFRunLoopBeforeTimers:
                   NSLog(@"即将进入Timers");
               break;
               case kCFRunLoopBeforeSources:
                   NSLog(@"即将进入Source");
               break;
               case kCFRunLoopBeforeWaiting:
                   NSLog(@"即将进入休眠");
               break;
               case kCFRunLoopAfterWaiting:
                   NSLog(@"即将结束休眠");
               break;
               case kCFRunLoopExit:
                   NSLog(@"即将退出Loop");
               break;
               default:
                   break;
           }
    });
    
    /// RunLoop添加Observer
    /// @param CFRunLoopRef rl 相关监听的RunLoop,这里监听主线程的RunLoop
    /// @param CFRunLoopObserverRef observer 创建的CFRunLoopObserver
    /// @param CFRunLoopMode RunLoop的模式<kCFRunLoopCommonModes包含两种模式>
    
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    CFRelease(observer);

和上面的方法一,大同小异,只不过是回调方法换成了block
测试一下

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"点击了屏幕 -- ");
}
即将结束休眠
即将进入Timers
即将进入Source
点击了屏幕 -- 

可以看到相关的监听
测试下Mode的切换

// CFRunLoopObserverCallBack 按照这个方法的格式进行创建
void myCFRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    CFRunLoopMode mode;
    switch (activity) {
        case kCFRunLoopEntry:
            
            mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
            NSLog(@"即将进入Loop  %@",mode);
            CFRelease(mode);
            break;
//        case kCFRunLoopBeforeTimers:
//            NSLog(@"即将进入Timers");
//        break;
//        case kCFRunLoopBeforeSources:
//            NSLog(@"即将进入Source");
//        break;
//        case kCFRunLoopBeforeWaiting:
//            NSLog(@"即将进入休眠");
//        break;
//        case kCFRunLoopAfterWaiting:
//            NSLog(@"即将结束休眠");
//        break;
        case kCFRunLoopExit:
            mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
            NSLog(@"即将退出Loop  %@",mode);
            CFRelease(mode);
        break;
        default:
            break;
    }
}

给当前界面添加一个ScrollView,滚动下查看相关的监听,在滑动开始和滑动结束,会发现相关Mode的切换情况

即将退出Loop  kCFRunLoopDefaultMode
即将进入Loop  UITrackingRunLoopMode
即将退出Loop  UITrackingRunLoopMode
即将进入Loop  kCFRunLoopDefaultMode
上一篇下一篇

猜你喜欢

热点阅读