通过为RunLoop添加监听器, 查看RunLoop的运行
2016-06-16 本文已影响851人
面糊
通过为RunLoop添加监听器, 查看RunLoop的运行
-
首先, 回顾RunLoop的几个事件
- Timer事件: 处理定时器等事物
- Source事件: 处理UI交互(只要点击屏幕, 都会触发Source事件)
- 当前的Timer和Source事件都处理结束的时候, 就会准备进入休眠状态
-
测试用的代码, 并在之后会做出一些分析
- (void)viewDidLoad { [super viewDidLoad]; [self addObserver]; // 添加监听者 NSLog(@"%@", [NSRunLoop currentRunLoop].currentMode); // 查看当前的RunLoop运行状态 } // 开启一个定时器 - (IBAction)btn:(id)sender { [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(getCurrentRunLoopMode) userInfo:nil repeats:YES]; } // 添加一个监听者 - (void)addObserver { // 1. 创建监听者 /** * 创建监听者 * * @param allocator#> 分配存储空间 * @param activities#> 要监听的状态 * @param repeats#> 是否持续监听 * @param order#> 优先级, 默认为0 * @param observer 观察者 * @param activity 监听回调的当前状态 */ CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { /* kCFRunLoopEntry = (1UL << 0), 进入工作 kCFRunLoopBeforeTimers = (1UL << 1), 即将处理Timers事件 kCFRunLoopBeforeSources = (1UL << 2), 即将处理Source事件 kCFRunLoopBeforeWaiting = (1UL << 5), 即将休眠 kCFRunLoopAfterWaiting = (1UL << 6), 被唤醒 kCFRunLoopExit = (1UL << 7), 退出RunLoop kCFRunLoopAllActivities = 0x0FFFFFFFU 监听所有事件 */ switch (activity) { case kCFRunLoopEntry: NSLog(@"进入"); break; case kCFRunLoopBeforeTimers: NSLog(@"即将处理Timer事件"); break; case kCFRunLoopBeforeSources: NSLog(@"即将处理Source事件"); break; case kCFRunLoopBeforeWaiting: NSLog(@"即将休眠"); break; case kCFRunLoopAfterWaiting: NSLog(@"被唤醒"); break; case kCFRunLoopExit: NSLog(@"退出RunLoop"); break; default: break; } }); // 2. 添加监听者 /** * 给指定的RunLoop添加监听者 * * @param rl#> 要添加监听者的RunLoop * @param observer#> 监听者对象 * @param mode#> RunLoop的运行模式, 填写默认模式即可 */ CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode); } - (void)getCurrentRunLoopMode{ // 每次定时器触发, 都去查看当前的RunLoop的运行mode NSLog(@"%@", [NSRunLoop currentRunLoop].currentMode); }
-
如果此时添加了Timer事件, 并且随时出发Source事件的话, 通过下面的打印, 可以判断一些情况
-
当App程序启动的时候, RunLoop会进入
UIInitializationRunLoopMode
模式, 这时在处理UI的准备工作 -
随后RunLoop会进入工作
-
在即将处理事件的时候, RunLoop会从休眠中被唤醒, 进入被唤醒的状态
kCFRunLoopAfterWaiting
-
然后会第一时间处理Timer的事件
-
处理之后, 查看是否还有Timer需要处理
-
然后检查是否还有Source需要处理
-
这时没有事件需要处理, 则准备进行休眠, 并且进行休眠
-
当Timer再次触发时, RunLoop被唤醒, 并继续进行上面的步骤
2016-06-16 02:18:07.805 test[842:40927] 即将休眠 2016-06-16 02:18:09.804 test[842:40927] 被唤醒 2016-06-16 02:18:09.805 test[842:40927] kCFRunLoopDefaultMode 2016-06-16 02:18:09.805 test[842:40927] 即将处理Timer事件 2016-06-16 02:18:09.805 test[842:40927] 即将处理Source事件 2016-06-16 02:18:09.806 test[842:40927] 即将休眠 2016-06-16 02:18:11.804 test[842:40927] 被唤醒 2016-06-16 02:18:11.805 test[842:40927] kCFRunLoopDefaultMode 2016-06-16 02:18:11.805 test[842:40927] 即将处理Timer事件 2016-06-16 02:18:11.805 test[842:40927] 即将处理Source事件 2016-06-16 02:18:11.806 test[842:40927] 即将休眠
-
-
另一个注意点:
-
如果在Timer运行的过程中, 监听到Source事件, 比如触摸屏幕
-
这时RunLoop会被唤醒, 然后处理Source事件, 并且之后再次进行上面的步骤, 直到休眠, 再次被唤醒
2016-06-16 02:28:37.218 test[842:40927] 被唤醒 2016-06-16 02:28:37.219 test[842:40927] 即将处理Timer事件 2016-06-16 02:28:37.219 test[842:40927] 即将处理Source事件 2016-06-16 02:28:37.220 test[842:40927] 即将处理Timer事件 2016-06-16 02:28:37.220 test[842:40927] 即将处理Source事件 2016-06-16 02:28:37.220 test[842:40927] 即将休眠 2016-06-16 02:28:37.420 test[842:40927] 被唤醒 2016-06-16 02:28:37.420 test[842:40927] 即将处理Timer事件 2016-06-16 02:28:37.421 test[842:40927] 即将处理Source事件 2016-06-16 02:28:37.421 test[842:40927] 即将休眠 2016-06-16 02:28:37.423 test[842:40927] 被唤醒 2016-06-16 02:28:37.423 test[842:40927] 即将处理Timer事件 2016-06-16 02:28:37.423 test[842:40927] 即将处理Source事件 2016-06-16 02:28:37.424 test[842:40927] 即将休眠 2016-06-16 02:28:37.841 test[842:40927] 被唤醒
-