iOS中的Runloop
本节主要理解:
1.runloop的理解与介绍(相关类与mode)
2.runloop在开发中的应用(主动使用/隐性调用)
3.runloop与线程的关系
4.Runloop与NSTimer的关系
■应用范畴
口 定时器( Timer )、PerformSelector
口 GCD Async Main Queue
口 事件响应、手势识别、界面刷新
口 网络请求
口 AutoreleasePool
伪代码
int main (int argc ,char * argv[]) [
@autoreleasepool {
int retVal = 0;
do {
//睡眠中等待消息
int message = sleep_ and_ _wait();
//处理消息
retVal = process. _message (message) ;
} while (0 == retVal);
return 0;
}
}
一.runloop相关的类
Core Foundation关于RunLoop5↑类
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
他们之间的关系可以用下图表示
图片.png
■Source0
触摸事件处理(事件响应)
口performSe lector: onThread :
Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。
■Source1
口基于Port的线程间通信
口系统事件捕捉
Source1 包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程。
■Timers
口NSTimer
口perform Selector:with0bject :afterDelay:
■Observers
口用于监听RunLoop的状态
口UI刷新( BeforeWaiting )
口 Autorelease pool ( BeforeWaiting )
二.RunloopMode
常见的2种Моdе
kCFRunLoopDefaultMode ( NSDefaultRunLoopMode ) : App的默认mode,通常主线程是在这个mode下运行
UITrackingRunLoopMode :界面跟踪mode,用于scrollview追踪触摸滚动,保证界面滑动时不受其他mode影响
当使用kCFRunLoopCommonModes模式监听runloop时,以上两种模式都将被监听到
二.Runloop在实际开发中的应用
1.控制线程的生命周期(线程保活)-如AFNetworking
往runloop中添加Source/Timer/Observer
run方法时无法停止的,它专门用来开启一个永不销毁的线程
[NSRunloop currentrunloop] run];
2.解决NSTimer在滑动时停止工作的问题
NSTimer是由RunLoop来管理的,NSTimer其实就是CFRunLoopTimerRef。
因为runloop只能运行在一种模式下,滚动时,会模式切换。
使用NSRunLoopCommonModes,会让NSTimer在两种模式下工作
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%d", ++count);
}];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// NSDefaultRunLoopMode、UITrackingRunLoopMode才是真正存在的模式
// NSRunLoopCommonModes并不是一个真的模式,它只是一个标记
// timer能在_commonModes数组中存放的模式下工作
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
3.监控应用卡顿/性能优化
可以添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的
面试题
1.讲讲RunLoop, ,项目中有用到吗?
-控制线程的生命周期/调度,(线程保活/线程间通讯切换)
解决NSTimer在滚动时停止工作的问题
监控应用卡顿
性能优化
2.runloop内部实现逻辑 ?
实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。
3.runloop和线程的关系 ?
一个线程对应一个runloop
线程在执行完任务后,会处于休眠状态,随时等待接受新的任务,而不是退出
只有主线程的RunLoop是默认开启的,所以程序在开启后,会一直运行,不会退出。其他线程的RunLoop如果需要开启,就手动开启
4.NSTimer 与runloop的关系?
1.NSTimer是由RunLoop来管理的,NSTimer其实就是CFRunLoopTimerRef。
2.子线程中创建Timer要将其Runloop开启[[NSRunLoop currentRunLoop]run];否则会不执行Timer事件
5.程序中添加每3秒响应一 次的NSTimer ,当拖动tableview时timer可能无法响应要怎么解决?
NSTimer是由RunLoop来管理的,NSTimer其实就是CFRunLoopTimerRef。
因为runloop只能运行在一种模式下,滚动时,会模式切换。
使用NSRunLoopCommonModes,会让NSTimer在两种模式下工作
6.runloop 是怎么响应用户操作的,具体流程是什么样的?
(简介版:由source1接收事件,由source0响应触摸事件)
用户交互事件首先在 IOHID 层生成 HIDEvent,然后向事件处理线程的 Source1 的 mach port 发送 HIDEvent 消息,Source1 的回调函数将事件转化为 UIEvent 并筛选需要处理的事件推入待处理事件队列,向主线程的事件处理 Source0 发送信号,并唤醒主线程,主线程检查到事件处理 Source0 有待处理信号后,触发 Source0 的回调函数,从待处理事件队列中提取 UIEvent,最后进入 hit-test 等 UIEvent 事件响应流程。
7.说说runLoop的几种状态
8.runloop的mode作用是什么 ?
model 主要是用来指定事件在运行循环中的优先级的,分为:
- NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
- UITrackingRunLoopMode :ScrollView滑动时
- UIInitializationRunLoopMode :启动时
- NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集
参考
runloop详解