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的知识小记的更多相关文章

  1. Runloop基础知识

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  2. EF基础知识小记四(数据库=>模型设计器)

    EF基础知识小记三(设计器=>数据库)介绍了如何创建一个空设计器模型,并如何将模型同步到数据库的表中,本文则主要介绍如何将一个存在的数据库同步到模型设计器中.为了能快速的模拟这个过程,给出一下建 ...

  3. Linq基础知识小记四之操作EF

    1.EF简介 EF之于Linq,EF是一种包含Linq功能对象关系映射技术.EF对数据库架构和我们查询的类型进行更好的解耦,使用EF,我们查询的对象不再是C#类,而是更高层的抽象:Entity Dat ...

  4. RunLoop总结:RunLoop基础知识

    没有实际应用场景,很难理解一些抽象空洞的东西,所以前面几篇文章先介绍了RunLoop的几个使用场景. 另外AsyncDisplayKit中也有大量使用RunLoop的示例. 关于实际的使用RunLoo ...

  5. RunLoop相关知识的总结

    RunLoop 即运行循环,也叫事件循环,本质为一个死循环.iOS一个程序运行起来之后,默认会开启一个运行循环,有需要处理的操作时,比如用户的输入事件时,RunLoop会自己跑起来运行,没有需要处理的 ...

  6. IOS知识小记

    iOS开发 小知识点 http://www.cnblogs.com/tangbinblog/archive/2012/07/20/2601324.html Objective-C中的instancet ...

  7. RunLoop相关知识

    RunLoop,翻译过来是运行环路.我们在创建命令行项目和创建ios项目时,发现命令行项目当最后一行代码执行完后项目就自动退出了,而ios项目确可以一直运行,知道用户手动点击退出按钮.这就是因为ios ...

  8. RunLoop基础知识以及GCD

    - 1.1 字面意思   a 运行循环   b 跑圈   - 1.2 基本作用(作用重大)   a 保持程序的持续运行(ios程序因而能一直活着不会死)    b 处理app中的各种事件(比如触摸事件 ...

  9. java基本知识小记(1)

    1.Java中的值传递 值传递意味着对于传给方法的每个参数都会制作一份副本然后将副本而不是原始值传递给方法并且通过参数的名进行引用. 注意:虽然传值机制对于所有参数类型都适用,但是他对对象类型的作用与 ...

随机推荐

  1. SSM框架之SpringMVC(2)参数绑定及自定义类型转换

    SpringMVC(2)参数绑定及自定义类型转换 1.请求参数的绑定 1.1. 请求参数的绑定说明 1.1.1.绑定机制 表单提交的数据都是k=v格式的 username=haha&passw ...

  2. 松软科技前端课堂:JavaScript 数值方法

    Number 方法帮助您处理数值. Number 方法和属性 原始值(比如 3.14 或 2016),无法拥有属性和方法(因为它们不是对象). 但是通过 JavaScript,方法和属性也可用于原始值 ...

  3. echarts背景颜色渐变的三种类型

    // 线性渐变,多用于折线柱形图,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,如果 globalCoord 为 `true`,则该四个值是绝对的 ...

  4. Android App图片资源文件压缩利器McImage

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/195 Android App图片资源文件压缩利器McIma ...

  5. Google Admob移动广告快速集成步骤

    Google Admob移动广告快速集成步骤 第一步:引入依赖包 //admob广告 implementation 'com.google.android.gms:play-services-ads: ...

  6. 树莓派设置frpc开机启动

    1.复制frpc启动命令及配置文件到系统相应目录: $ sudo cp frpc /usr/local/bin/frpc $ sudo mkdir /etc/frpc $ sudo cp frpc.i ...

  7. Error 942 occured during Initialization of Bufq KUPC$S_1_20181023155636

      一台ORACLE实例(Oracle Database 10g Release 10.2.0.5.0)启动时,报"Error 942 occured during Initializati ...

  8. 迁移到MAC

    周末折腾了2天环境,主要是从windows迁移到mac上,提升逼格告别山寨,迈向专业化.首先,终于把pomelo的c客户端在xcode上跑起来了,至此已基本解决了网络连接问题.由于是第一次用mac开发 ...

  9. CodeForces 862B(思维+二分图染色)

    题意 https://vjudge.net/problem/CodeForces-862B 给出n个点,n-1条边,求再最多再添加多少边使得二分图的性质成立 思路 因为题目是求的最多添加多少边,所以可 ...

  10. 记录python上传文件的坑(1)

    import random import string import requests from requests_toolbelt import MultipartEncoder f = '2019 ...