什么是Runloop
运行循环,在程序运行中做事情
- 定时器,performSelector
- GCD Async queue
- 事件响应,手势识别,页面刷新
- 网络请求
- autoreleasepool
卡顿检测 https://www.jianshu.com/p/d0aab0eb8ce4
新开线程,用 while YES 加一个信号量,在 回调(runloop循环会调用)中去打开信号量,计算次数
卡顿时runloop在做什么 activity == kCFRunLoopBeforeSources || activity == kCFRunLoopAfterWaiting
休眠时 before Waiting
1s 看任务情况大概几个几十个循环都有可能
runloop底层结构
结构体,内部有_pthread/commonModes/commonModelItems/_currentMode 和modes
其中 modes 里面装的是 各种模式。
每个模式里面有 name, source0,source1,obsevers,timer (都是set)
- 一个runloop包含若干mode,每个mode包含若干 source0/source1/timer/Observer
- 每次只能选择一个mode,切换mode需要退出当前loop,重新选择
- 不同组的source0/source1/timer/observer互不干扰
- mode没有事件会立即退出
runloop与线程
每条线程都有与之对应的runloop对象
runloop保存在全局的dictionary,key=线程,value=runloop
线程刚创建不会有runloop对象,第一次获取时创建
runloop在线程结束时销毁
主线程默认开启runloop,子线程默认没有开启
常见2种mode
default 默认
tracking scrollview
runloop运行逻辑
- 通知 observers 进入loop
- 通知 observers 即将处理timer
- observers 即将处理sources
- 处理 blocks
- 处理source0
- 如存在source1 ->8
- 通知 observers 开始休眠
- 通知 observers 结束休眠 (处理 timer,GCD Async To Main Queue,source1)
- 处理 Blocks
- 根据结果继续 runloop或者 退出
- 通知 observers 退出 loop
Source0:触摸事件,performSelector:onTnread:
Source1:port通信,系统事件捕捉
Source1 :基于mach_Port的,来自系统内核或者其他进程或线程的事件,可以主动唤醒休眠中的RunLoop(iOS里进程间通信开发过程中我们一般不主动使用)。mach_port大家就理解成进程间相互发送消息的一种机制就好, 比如屏幕点击, 网络数据的传输都会触发sourse1。
• Source0 :非基于Port的 处理事件,什么叫非基于Port的呢?就是说你这个消息不是其他进程或者内核直接发送给你的。一般是APP内部的事件, 比如hitTest:withEvent的处理, performSelectors的事件.
简单举个例子:一个APP在前台静止着,此时,用户用手指点击了一下APP界面,那么过程就是下面这样的:
我们触摸屏幕,先摸到硬件(屏幕),屏幕表面的事件会被IOKit先包装成Event,通过mach_Port传给正在活跃的APP , Event先告诉source1(mach_port),source1唤醒RunLoop, 然后将事件Event分发给source0,然后由source0来处理。
Timers:NSTimer,performSelector:withObject:afterDelay:
Observes: 监控runloop状态,UI刷新(before waiting),AutoreleasePool(before waiting)
runloop运用
- 线程保活
- 解决NSTimer滑动停止
- 监控卡顿,性能优化