IOS精选文集移动开发技术前沿iOS精英班

通过为RunLoop添加监听器, 查看RunLoop的运行

2016-06-16  本文已影响851人  面糊

通过为RunLoop添加监听器, 查看RunLoop的运行

  1. 首先, 回顾RunLoop的几个事件

    • Timer事件: 处理定时器等事物
    • Source事件: 处理UI交互(只要点击屏幕, 都会触发Source事件)
    • 当前的Timer和Source事件都处理结束的时候, 就会准备进入休眠状态
  2. 测试用的代码, 并在之后会做出一些分析

     - (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);
     }
    
  3. 如果此时添加了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] 即将休眠
      
  4. 另一个注意点:

    • 如果在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] 被唤醒
上一篇下一篇

猜你喜欢

热点阅读