博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RunLoop的唤醒探索
阅读量:7189 次
发布时间:2019-06-29

本文共 2935 字,大约阅读时间需要 9 分钟。

概况

屏幕触摸事件,定时器事件是常见的可以唤醒runLoop的事件。但是我们很少去关注定时器是怎么唤醒额runLoop,唤醒后又进行了哪些操作。我们也很少关注我们触摸屏幕如点击一个按钮,是如何唤醒的runLoopo,唤醒多经历了哪些过程,点击完按钮又执行了什么。下边让我们来逐一探索。

定时器事件唤醒runLoop

  1. 首先我们先写个类去监听runLoop的状态
@implementation MainRunLoopObsever+ (void)load{    CFRunLoopObserverRef obseverRef = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {        NSString *str = nil;        switch (activity) {            case kCFRunLoopEntry:                str = @"kCFRunLoopEntry";                break;            case kCFRunLoopBeforeTimers:                str = @"kCFRunLoopBeforeTimers";                break;            case kCFRunLoopBeforeSources:                str = @"kCFRunLoopBeforeSources";                break;            case kCFRunLoopBeforeWaiting:                str = @"kCFRunLoopBeforeWaiting";                break;            case kCFRunLoopExit:                str = @"kCFRunLoopExit";                break;            case kCFRunLoopAllActivities:                str = @"kCFRunLoopAllActivities";                break;            case kCFRunLoopAfterWaiting:                str = @"kCFRunLoopAfterWaiting";                break;                            default:                break;        }        if (str == nil) {            NSLog(@"%ld",activity);        }else{            NSLog(@"%@",str);        }    });        CFRunLoopAddObserver(CFRunLoopGetMain(), obseverRef, kCFRunLoopCommonModes);}@end复制代码
  1. 之后再写定时器代码
@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];        [NSTimer scheduledTimerWithTimeInterval:10.0 repeats:YES block:^(NSTimer * _Nonnull timer) {        NSLog(@"timer事件");    }];}@end复制代码
  1. 观察控制台的打印
    在NSLog部分打个断点,程序运行起来,观察控制台的打印。发现在控制台输入kCFRunLoopAfterWaiting之后进入了断点执行了我们写的block,之后我们在解除断点跑起来程序发现之后依次输出timer事件,kCFRunLoopBeforeTimers,kCFRunLoopBeforeSources,kCFRunLoopBeforeWaiting。
    说明定时器事件唤醒了runLoop之后执行了kCFRunLoopAfterWaiting这个obsever。之后执行我们的定时任务输出timer事件,在执行完毕后执行了kCFRunLoopBeforeTimers(obsever),再之后执行了kCFRunLoopBeforeSources(obsever),最后执行了kCFRunLoopBeforeWaiting(obsever)。之后其实要倾倒释放池,重新创建新的释放池,并更新UI,最后CPU进入睡眠态。

屏幕事件唤醒runLoop

  1. 屏幕事件唤醒runLoop稍复杂些。唤醒前要经历一些系统的处理
  2. 当我们点击一个按钮后系统的IOKit.framework会生成一个IOHIDEvent事件。这个事件先经过springBoard进行过滤(目的是看是否是摇晃事件,音量事件等)
  3. 过滤后确认是屏幕事件。这时候会通过matchPoart触发source1事件,source1事件唤醒了runLoop。
  4. 之后执行kCFRunLoopAfterWaiting这个obsever。然后去处理source1,之后执行kCFRunLoopBeforeTimers(obsever),再之后执行了kCFRunLoopBeforeSources(obsever),之后执行了source0事件
  5. 该事件内部把IOHIDEvent事件封装成了UIEvent事件。并触发了响应链规则(即先通过hitTest,pointInside两个方法找到点击的那个view,之后通过响应链来找到要执行的方法。然后去执行这个方法)执行完source0后,会继续检查是否有source1事件了如果有就去执行,再一次循环(这样做的目的在于省去了cpu睡眠时间,任务多就去直接执行即可)。
  6. 之后执行了kCFRunLoopBeforeWaiting,倾倒释放池,创建新的释放池,并更新UI,这时候我们就看到了界面的UI变化了。这也解释了,为什么只有与当程序完全跑起来了,cpu进入睡眠了才可以看到UI界面的变化。
  7. 由于以上执行过程较为复杂,所以就不一一验证了。另外hiteTest,pointInside两个方法也很巧妙的可以确定当前view。也是值得我们研究的。这里也不一一解释了,有兴趣的去找度娘吧,大把大把的解释。

转载于:https://juejin.im/post/5cf1da1ef265da1ba328ac3f

你可能感兴趣的文章
Largest Point
查看>>
构建高可靠hadoop集群之4-权限指引
查看>>
用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
查看>>
数据库
查看>>
React:redux+router4搭建应用骨架
查看>>
13.文档模板架构
查看>>
动态规划之硬币组合问题
查看>>
冲刺二阶段———个人总结02
查看>>
css第四课时
查看>>
BUAA_OO_第三单元
查看>>
通讯录的输入输出
查看>>
工具类
查看>>
【动态规划】bzoj1613 [Usaco2007 Jan]Running贝茜的晨练计划
查看>>
delphi實現按键精靈的功能
查看>>
Ubuntu 13.04有线连接异常
查看>>
DB2 错误解释
查看>>
JAVA面试考点解析(7):分布式架构、微服务治理
查看>>
C++ 异常处理
查看>>
Intrumetation单元测试框架
查看>>
Struts2中param的作用
查看>>