RunLoop的知识小记
RunLoop字面上的意思是,运行循环;
其基本作用:保持程序的持续运行;
处理App中的各种事件(比如:触摸事件、定时器事件、Selector事件)
节省CPU资源,提高程序性能:该做事时做事,该休息时休息
1.main函数中的RunLoop
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
} 在这个main函数中,UIApplicationMain函数内部就启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,保持了程序的持续运行。这个默认启动的RunLoop是跟主线程相关联的。
NSRunLoop 是基于CFRunLoopRef的一层OC包装,所以了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API。
2.RunLoop与线程的关系
每条线程都有唯一的一个与之对应的RunLoop对象
主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
RunLoop在第一次获取时创建,在线程结束时销毁
获取子线程对应的RunLoop(即,currentRunLoop)该方法本身是懒加载的,如果第一次调用就会创建当前线程对应的RunLoop并保存,以后调用则直接获取
3.RunLoop的获取
#pragma mark - RunLoop
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//OC语言中的API
//01 获取主线程对应的runloop对象
NSRunLoop *mainRunloop = [NSRunLoop mainRunLoop];
//02 获取当前的runloop的对象
NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
NSLog(@"%p---%p", mainRunloop, currentRunloop); //C语言的API
//01 主运行循环
CFRunLoopRef mainRunloopRef = CFRunLoopGetMain();
//02 当前的运行循环
CFRunLoopRef currentRunloopRef = CFRunLoopGetCurrent();
NSLog(@"%p---%p", mainRunloopRef, currentRunloopRef); //转化
NSLog(@"%p----%p", mainRunloop.getCFRunLoop, mainRunloopRef);
}
打印的结果:
-- ::31.176193+ NSCach[:] 0x60000184c060---0x60000184c060
-- ::31.176302+ NSCach[:] 0x600000050600---0x600000050600
-- ::31.176362+ NSCach[:] 0x600000050600----0x600000050600
可以看出,当前的主运行循环和当前运行循环是同一个runloop, 最后一行可以看出,OC获取的runloop与C的runloop可以相互转化。
4.RunLoop的模式与Timer的关系
//Runloop的运行模式和Timer
- (void)RunLoopModeAndTimer {
//创建定时器对象
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
//添加到runloop中
//Mode:runloo的运行模式(默认|界面跟踪|占位)
//把定时器对象添加到runloop中,并制定运行模式为默认--当运行模式为NSDefaultRunLoopMode的时候,定时器才会工作
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; //当滚动textView的时候,主运行循环会切换运行模式:从默认切换成界面跟踪运行模式
//把定时器对象添加到runloop中,并制定运行模式为界面跟踪--当运行模式为UITrackingRunloopMode的时候(即拖拽界面时),定时器才会工作
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; //当两种模式都可以运行时,均可用
//把定时器对象添加到runloop中,并制定运行模式为NSRunLoopCommonModes--当运行模式为NSDefaultRunLoopMode或者UITrackingRunloopMode的时候,定时器才会工作
//需要注意没有NSRunLoopCommonModes这种模式,NSRunLoopCommonModes是标记NSDefaultRunLoopMode或者UITrackingRunloopMode的集合
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
} - (void)run {
NSLog(@"run----%@", [NSRunLoop currentRunLoop].currentMode);
}
注意
//该方法内部会自动创建的定时器对象添加到当前的runloop,并且指定运行模式为默认
// [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; //如果想利用上面的那种方法,修改运行模式,可修改成如下
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
注意:上面添加的定时器,如果是添加在主线程中的,所以,不需要开始runloop,定时器就可以工作;但是如果,直接添加到子线程中,例如下面的代码:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self performSelectorInBackground:@selector(RunLoopModeAndTimer) withObject:nil];
}
- (void)RunLoopModeAndTimer { //该方法内部会自动创建的定时器对象添加到当前的runloop,并且指定运行模式为默认
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; } - (void)run {
NSLog(@"run----%@", [NSRunLoop currentRunLoop].currentMode);
}
那么,点击界面的时候,定时器是不工作的;因为定时器对象添加到当前的runloop中,而当前的runloop在子线程中;子线程中的runloop需要手动创建,所以此时定时器不工作。
解决方式:开启runloop
- (void)RunLoopModeAndTimer { //该方法内部会自动创建的定时器对象添加到当前的runloop,并且指定运行模式为默认
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
5.GCD的定时器
按照上面那段代码执行后,会发现,timer并没有执行。因为在程序运行到 } 后,代码就执行完了,就被释放了。所以需要添加一个强引用。
修改如下:
总结:
Runloop的相关类
Core Foundation中关于RunLoop的5个类:
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
当runloop选择一个运行模式后,需要判断运行模式是否为空,判断的依据是:Source和Timer是否有数据,如果没有数据,runloop立马退出。
选择了一个运行模式后
如果source或者timer有数据时,就开启runloop。
RunLoopObserver简单说明
CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变。
可以监听的时间点有以下几个:
RunLoop的知识小记的更多相关文章
- Runloop基础知识
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- EF基础知识小记四(数据库=>模型设计器)
EF基础知识小记三(设计器=>数据库)介绍了如何创建一个空设计器模型,并如何将模型同步到数据库的表中,本文则主要介绍如何将一个存在的数据库同步到模型设计器中.为了能快速的模拟这个过程,给出一下建 ...
- Linq基础知识小记四之操作EF
1.EF简介 EF之于Linq,EF是一种包含Linq功能对象关系映射技术.EF对数据库架构和我们查询的类型进行更好的解耦,使用EF,我们查询的对象不再是C#类,而是更高层的抽象:Entity Dat ...
- RunLoop总结:RunLoop基础知识
没有实际应用场景,很难理解一些抽象空洞的东西,所以前面几篇文章先介绍了RunLoop的几个使用场景. 另外AsyncDisplayKit中也有大量使用RunLoop的示例. 关于实际的使用RunLoo ...
- RunLoop相关知识的总结
RunLoop 即运行循环,也叫事件循环,本质为一个死循环.iOS一个程序运行起来之后,默认会开启一个运行循环,有需要处理的操作时,比如用户的输入事件时,RunLoop会自己跑起来运行,没有需要处理的 ...
- IOS知识小记
iOS开发 小知识点 http://www.cnblogs.com/tangbinblog/archive/2012/07/20/2601324.html Objective-C中的instancet ...
- RunLoop相关知识
RunLoop,翻译过来是运行环路.我们在创建命令行项目和创建ios项目时,发现命令行项目当最后一行代码执行完后项目就自动退出了,而ios项目确可以一直运行,知道用户手动点击退出按钮.这就是因为ios ...
- RunLoop基础知识以及GCD
- 1.1 字面意思 a 运行循环 b 跑圈 - 1.2 基本作用(作用重大) a 保持程序的持续运行(ios程序因而能一直活着不会死) b 处理app中的各种事件(比如触摸事件 ...
- java基本知识小记(1)
1.Java中的值传递 值传递意味着对于传给方法的每个参数都会制作一份副本然后将副本而不是原始值传递给方法并且通过参数的名进行引用. 注意:虽然传值机制对于所有参数类型都适用,但是他对对象类型的作用与 ...
随机推荐
- leaflet 实现克里金插值功能(附源码下载)
前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...
- Spring高级注解
目录: 1.使用限定注解:2.自定义限定注解:3.自定义bean的生命周期: 开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8新建一个名称为demo的Spr ...
- KumuluzEE - Java EE的微服务框架
KumuluzEE - Java EE的微服务架构 https://www.jdon.com/soa/kumuluzEE.html
- May 19th, 2019. Week 21st, Sunday
Fight for what matters to you. 为自己珍视的东西奋斗吧! We all want to make our life goals true, and we all expe ...
- 自定义v-color指令
在自定义指令的时候,和js行为有关的,最好就写在inserted中去,防止js代码不生效.和样似有关的操作放在bind中去Vue.direactive [d儿 Rai K T V] 没有s哈 < ...
- 2015 经典的ImageCaptioning论文
1.Show and Tell: A Neural Image Caption Generator Google团队的成果 整体处理流程: 1)通过CNN提取到图片的特征,简称feature. 2)而 ...
- Java Web 学习(6) —— Spring MVC 之校验器
Spring MVC 之校验器 数据验证 一个典型的 Spring MVC 应用会同时应用到 formatters/converters 和 validators. 在调用 controller 期间 ...
- 《3D_Deep_Learning_for_Robot_Perception.pdf》
https://github.com/PrincetonVision/marvin
- phoenix中添加二级索引
Phoenix创建Hbase二级索引 官方文档 1. 配置Hbase支持Phoenix创建二级索引 1. 添加如下配置到Hbase的Hregionserver节点的hbase-site.xml ...
- 【LOJ2402】「THUPC 2017」天天爱射击 / Shooting(整体二分)
点此看题面 大致题意: 有\(n\)个区间,每个区间有一个权值,当权值变成\(0\)时消失.每个时刻将覆盖某一位置的所有区间权值减\(1\),求每个时刻有多少个区间在这一刻消失. 前言 整体二分裸题啊 ...