1.讲讲RunLoop,项目中有用到吗?
RunLoop顾名思义就是程序在运行过程中循环做一些事情.如果没有RunLoop的话,程序运行结束以后就会马上退出的.而我们OC的main函数系统自动为我们创建了RunLoop函数,所以程序并不会马上退出,而是保持运行状态,监听用户的相关操作.
RunLoop的基本作用:
- 保持程序的持续运行;
- 处理App中的各种事件(比如触摸事件,定时器事件等)
- 节约CPU资源,提高程序性能.该做事的时候做事,该休息的时候休息.
RunLoop 的应用范畴:
- 定时器,
- GCD Async Main Queue,
- 事件响应,
- 手势识别,
- 界面刷新,
- 网络请求,
- AutoreleasePool,
- performSelector:on Thread
RunLoop 对象:
ios中有2套API来访问和使用RunLoop:
- 方式一:Foundation框架中的:NSRunLoop
- 方式二:Core Foundation框架中的:CFRunLoopRef(开源的)
NSRunLoop和CFRunLoopRef都代表着RunLoop对象,而 NSRunLoop是对CFRunLoopRef的一层OC封装.
获取RunLoop的对象:
[NSRunLoop currentRunLoop];//获取当前线程的RunLoop
[NSRunLoop mainRunLoop];//获取主线程的RunLoop
RunLoop 相关的五个类:
- CFRunLoopRef--->
NSRunLoop对象是OC对象,是对CFRunLoopRef的封装,可以通过getCFRunLoop方法获取其对应的CFRunLoopRef对象。注意,NSRunLoop不是线程安全的,但CFRunLoopRef是线程安全的
- CFRunLoopModeRef-->
NSRunLoop对象是一系列RunLoopMode的集合,每个mode包括有这个模式下所有的Source源、Timer源和观察者。每次RunLoop调用的时候都只能调用其中的一个mode,接收这个mode下的源,通知这个mode下的观察者。这样设计的主要目的就是为了隔离各个模式下的源和观察者,使其不相互影响,model有一下常用的五种:
-
2.1.kCFRunLoopDefaultMode:
-
App默认的mode,通常主线程就是在这个mode下运行的
2.2.UITrackingRunLoopMode:
-
界面跟踪时的mode,一般用于ScrollView滚动的时候追踪的,保证滑动的时候不受其他model的影响
2.3.UIInitializationRunLoopMode:
-
在刚启动 App 时进入的第一个 Mode,启动完成后就不再使用
2.4.GSEventReceiveRunLoopMode:
-
接受系统事件的内部 Mode,一般用不到
2.5.kCFRunLoopCommonModes:
-
占位mode,可以向其中添加其他mode用以检测多个mode的事件
-
3.CFRunLoopSourceRef--->事件源产生的地方
-
4.CFRunLoopTimerRef-->是基于事件的触发器,其中包含一段时间长度、延期容忍度和一个函数指针(回调方法)。当其加入到RunLoop中时,RunLoop会注册一个时间点,当到达这个时间点后,会触发对应的事件。
-
5.CFRunLoopObserverRef-->RunLoop的观察者。每个观察者都可以观察RunLoop在某个模式下事件的触发并处理
kCFRunLoopEntry:即将进入runLoop
kCFRunLoopBeforeTimers:即将处理Timer
kCFRunLoopBeforeSources:即将处理Source
kCFRunLoopBeforeWaiting:即将进入休眠
kCFRunLoopAfterWaiting:刚从休眠中被唤醒
kCFRunLoopExit:即将退出RunLoop
CFRunLoopModeRef代表RunLoop的运行模式
- 一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/ Source1/Timer/Observer
- RunLoop启动时只能选择其中一个Mode,作为currentMode
- 如果需要切换Mode,只能退出当前Loop,在重新选择一个Mode进入(这样做的好处是:不同组的Source0/ Source1/Timer/Observer能分隔开,互不影响)
- 如果Mode中没有任何Source0/ Source1/Timer/Observer,RunLoop会立马退出.
mode的分别处理的事件:
- Source0:处理触摸事件/perform Selectors
- Source1:处理基于Port的线程通信
- Timer:处理定时器/NSTimer
- Observer:处理监听器/用于监听RunLoop的状态.
总结:
首先CFRunloopRef这个对象里面有一个CFMutableSetRef _modes这个集合,而_modes这个集合里面装着一堆CFRunLoopModeRef model,当然有其中一个model代表当前的model(_currentModel).而CFRunLoopModeRef里面又装着很多CFMutableSetRef _sources0集合,CFMutableSetRef _sources1集合(sources0和sources1这个集合里面装着一堆CFRunLoopSourceRef对象),CFMutableArrayRef _observers集合(这个 集合里面装着一堆CFRunLoopObserverRef对象),tCFMutableArrayRef _timers集合(这个集合里面装着一堆CFRunLoopTimerRef对象)
2.RunLoop内部执行逻辑?
- 通知Observers ,进入Loop;
- 通知Observers,即将处理Timers;
- 通知Observers即将处理 Sources;
- 处理Blocks;
- 处理 Source0(可能会再次处理Blocks);
- 如果存在Source1,就会跳转到第8步处理Source1;
- 通知Observers开始休眠(一旦开始睡眠 了就需要等待消息进行唤醒);
- 如果被某个消息唤醒了就通知Observers结束休眠,开始处理相应的事件--->1.如果是Timer唤醒了就处理Timer;2.如果是GCD唤醒了就处理CGD;3.如果是Source1唤醒了就处理Source1.
- 处理Blocks->重新再处理一遍block;
- 根据当前的执行结果,决定如何操作是重新回到第2步执行还是直接退出Loop.
- 如果需要直接退出runloop,则通知Observers退出Loop
源码解析
3.RunLoop和线程的关系?
- 每条线程都有唯一的一个与之对应的RunLoop对象;
- RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为Value(源码可以证明);
- 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建;
- RunLoop会在线程结束时候销毁.
4.timer和RunLoop的关系?
/**
第一种方法:
1.此方法的创建定时器默认会加到了NSRunLoop中,并设置运行模式为默认.
2.如是想在子线程中开启NSRunLoop,需要手动开启:
NSRunLoop*runllop=[NSRunLoop currentRunLoop];等到线程销毁的时候currentRunLoop的对象也随之销毁;
3.在子线程的定时器,需要手动加入runLoop,不要忘记调用run方法
*/
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(startTime) userInfo:nil repeats:YES];
/**
第二种方法:
1.此方法创建需要手动将定时器添加到 NSRunLoop中,指定的运行模式是default,但是有滚动事件的时候,定时器就会停止工作.
解决方案:更改NSRunLoop的运行模式.UITrackingRunLoopMode界面追踪,此模式只有发生滚动事件的时候才会开启定时器.若是任何时候都会开启定时器:NSRunLoopCommonModes(NSRunLoopCommonModes=NSDefaultRunLoopMode+UITrackingRunLoopMode).凡是添加到NSRunLoopCommonModes中的事件都会被同时添加到CommonMode的运行模式上的.
*/
NSTimer*timer=[NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(startTime) userInfo:nil repeats:YES];
//下面这三种情况根据实际情况加入RunLoop
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode];
5.程序中添加每3秒响应一次的NSTimer,当拖动tableview时候timer可能无法响应要怎么解决?
将Timer添加到CommonModes类型里面.
6.RunLoop是怎么响应用户操作的,具体流程是什么样的?
7.说说RunLoop的几种状态?
8.RunLoop的model作用是什么?
视频讲解:
视频一:runLoop使用详情,视频讲解(一)-IOS文档类资源-CSDN下载
视频二:runLoop使用详情,视频讲解(二)-IOS文档类资源-CSDN下载
视频三:runLoop使用详情,视频讲解(三)-IOS文档类资源-CSDN下载
视频四:runLoop使用详情,视频讲解(四)-IOS文档类资源-CSDN下载
视频五:runLoop使用详情,视频讲解(五)-IOS文档类资源-CSDN下载
视频六:runLoop使用详情,视频讲解(六)-IOS文档类资源-CSDN下载
视频七:runLoop使用详情,视频讲解(七)-IOS文档类资源-CSDN下载