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中的值传递 值传递意味着对于传给方法的每个参数都会制作一份副本然后将副本而不是原始值传递给方法并且通过参数的名进行引用. 注意:虽然传值机制对于所有参数类型都适用,但是他对对象类型的作用与 ...
随机推荐
- PHP中RBAC权限管理
1.RBAC概念和原理 RBAC:全称叫做Role-Based Access Control,中文翻译叫做基于角色的访问控制.其主要的作用是实现项目的权限控制. ...
- for循环使用element的折叠面板遇到的问题-1
首先,效果是点击添加折叠面板,折叠面板的title右侧是关闭的小按钮,每次添加的面板都自动展开,其他的面板自动关闭,但其中发现一个问题是,每次点击关闭的时候,虽然上一个面板被关闭了,但他的下一个会自动 ...
- 简单学习HTML
最近突然就对静态页面很有兴趣,主要是看到几个比较酷炫的页面效果,也想自己做一下,但是我的前端页面就是菜鸡,还停留在html+css+jquery的简单使用上,而且还忘记得差不多了! 而且我感觉前端比后 ...
- JS 验证
JS 验证 JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证. JavaScript 表单验证 JavaScript 可用来在数据被送往服务器前对 HTML ...
- 【Gradle】Android Gradle 高级自定义
Android Gradle 高级自定义 使用共享库 Android的包,如android.app,android.content,android.view,android.widget等,是默认包含 ...
- Django用websocket实现聊天室之筑基篇
最近闲来无事,无意发现一个聊天室的前端UI,看着挺好看的但是没有聊天室的通信代码,于是想给它安装电池(通信部分),先看UI: 开始通信部分的工作: 使用的组件: Django1.11.13 chann ...
- 此 iCloud 帐户已经存在。
0x00 事件 将 Apple ID 换了一个邮箱,然后在 macOS 重新登陆的时候出现登录不上异常,始终显示 若要将此 Apple ID 用作主要的 iCloud 帐户,请从"互联网帐户 ...
- java 通过Qrcode生成二维码添加图片logo和文字描述
/** * 二维码创建 * @author yhzm * */ public class printServiceImpl extends BaseService { public void barC ...
- 201871010126 王亚涛 《面向对象程序设计 (Java)》第十六周学习总结
内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/12 ...
- UVA 12165 Triangle Hazard
https://cn.vjudge.net/problem/UVA-12165 题目 给出D.E.F分BC,CA,AB的比$m_1:m_2$,$m_3:m_4$,$m_5:m_6$和PQR三点的坐标, ...