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