1.Runloop基础知识

- 1.1 字面意思

a 运行循环

b 跑圈

- 1.2 基本作用(作用重大)

a 保持程序的持续运行(ios程序为什么能一直活着不会死)

b 处理app中的各种事件(比如触摸事件、定时器事件【NSTimer】、selector事件【选择器·performSelector···】)

c 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息

- 1.3 重要说明

(1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。

(2)如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行

(2)main函数中的Runloop

a 在UIApplication函数内部就启动了一个Runloop

该函数返回一个int类型的值

b 这个默认启动的Runloop是跟主线程相关联的

- 1.4 Runloop对象

(1)在iOS开发中有两套api来访问Runloop

a.foundation框架【NSRunloop】

b.core foundation框架【CFRunloopRef】

(2)NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换

(3)NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)

- 1.5 Runloop参考资料

objc

(1)苹果官方文档

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

(2)CFRunLoopRef开源代码下载地址:

http://opensource.apple.com/source/CF/CF-1151.16/

- 1.6 Runloop与线程

1.Runloop和线程的关系:一个Runloop对应着一条唯一的线程

问题:如何让子线程不死

回答:给这条子线程开启一个Runloop

2.Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建

3.Runloop的生命周期:在第一次获取时创建,在线程结束时销毁

- 1.7 获得Runloop对象

objc

1.获得当前Runloop对象

//01 NSRunloop

NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];

//02 CFRunLoopRef

CFRunLoopRef runloop2 =   CFRunLoopGetCurrent();

2.拿到当前应用程序的主Runloop(主线程对应的Runloop)

//01 NSRunloop

NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];

//02 CFRunLoopRef

CFRunLoopRef runloop2 =   CFRunLoopGetMain();

3.注意点:开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。

4.在子线程中,如果不主动获取Runloop的话,那么子线程内部是不会创建Runloop的。可以下载CFRunloopRef的源码,搜索_CFRunloopGet0,查看代码。

5.Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop。

- 1.8 Runloop相关类

(1)Runloop运行原理图

![PNG](2.png)

(2)五个相关的类

a.CFRunloopRef

b.CFRunloopModeRef【Runloop的运行模式】

c.CFRunloopSourceRef【Runloop要处理的事件源】

d.CFRunloopTimerRef【Timer事件】

e.CFRunloopObserverRef【Runloop的观察者(监听者)】

(3)Runloop和相关类之间的关系图

![PNG](1.png)

(4)Runloop要想跑起来,它的内部必须要有一个mode,这个mode里面必须有source\observer\timer,至少要有其中的一个。

- CFRunloopModeRef

1.CFRunloopModeRef代表着Runloop的运行模式

2.一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等

3.每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode

4.如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入

5.这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响

6.系统默认注册了5个mode

a.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

b.UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

c.UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用

d.GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到

e.kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

- CFRunloopTimerRef

(1)NSTimer相关代码

objc

/*

说明:

(1)runloop一启动就会选中一种模式,当选中了一种模式之后其它的模式就都不鸟。一个mode里面可以添加多个NSTimer,也就是说以后当创建NSTimer的时候,可以指定它是在什么模式下运行的。

(2)它是基于时间的触发器,说直白点那就是时间到了我就触发一个事件,触发一个操作。基本上说的就是NSTimer

(3)相关代码

*/

- (void)timer2

{

//NSTimer 调用了scheduledTimer方法,那么会自动添加到当前的runloop里面去,而且runloop的运行模式kCFRunLoopDefaultMode

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

//更改模式

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

}

- (void)timer1

{

//    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

//定时器添加到UITrackingRunLoopMode模式,一旦runloop切换模式,那么定时器就不工作

//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

//定时器添加到NSDefaultRunLoopMode模式,一旦runloop切换模式,那么定时器就不工作

//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

//占位模式:common modes标记

//被标记为common modes的模式 kCFRunLoopDefaultMode  UITrackingRunLoopMode

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

//    NSLog(@"%@",[NSRunLoop currentRunLoop]);

}

- (void)run

{

NSLog(@"---run---%@",[NSRunLoop currentRunLoop].currentMode);

}

- (IBAction)btnClick {

NSLog(@"---btnClick---");

}

(2)GCD中的定时器

objc

//0.创建一个队列

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

//1.创建一个GCD的定时器

/*

第一个参数:说明这是一个定时器

第四个参数:GCD的回调任务添加到那个队列中执行,如果是主队列则在主线程执行

*/

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

//2.设置定时器的开始时间,间隔时间以及精准度

//设置开始时间,三秒钟之后调用

dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW,3.0 *NSEC_PER_SEC);

//设置定时器工作的间隔时间

uint64_t intevel = 1.0 * NSEC_PER_SEC;

/*

第一个参数:要给哪个定时器设置

第二个参数:定时器的开始时间DISPATCH_TIME_NOW表示从当前开始

第三个参数:定时器调用方法的间隔时间

第四个参数:定时器的精准度,如果传0则表示采用最精准的方式计算,如果传大于0的数值,则表示该定时切换i可以接收该值范围内的误差,通常传0

该参数的意义:可以适当的提高程序的性能

注意点:GCD定时器中的时间以纳秒为单位(面试)

*/

dispatch_source_set_timer(timer, start, intevel, 0 * NSEC_PER_SEC);

//3.设置定时器开启后回调的方法

/*

第一个参数:要给哪个定时器设置

第二个参数:回调block

*/

dispatch_source_set_event_handler(timer, ^{

NSLog(@"------%@",[NSThread currentThread]);

});

//4.执行定时器

dispatch_resume(timer);

//注意:dispatch_source_t本质上是OC类,在这里是个局部变量,需要强引用

self.timer = timer;

- CFRunloopSourceRef

1.是事件源也就是输入源,有两种分类模式;

一种是按照苹果官方文档进行划分的

另一种是基于函数的调用栈来进行划分的(source0和source1)。

2.具体的分类情况

(1)以前的分法

Port-Based Sources

Custom Input Sources

Cocoa Perform Selector Sources

(2)现在的分法

Source0:非基于Port的

Source1:基于Port的

3.可以通过打断点的方式查看一个方法的函数调用栈

- CFRunLoopObserverRef

(1)CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

(2)如何监听

```objc

//创建一个runloop监听者

CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

NSLog(@"监听runloop状态改变---%zd",activity);

});

//为runloop添加一个监听者

CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

CFRelease(observer);

(3)监听的状态

objc

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {

kCFRunLoopEntry = (1UL << 0),   //即将进入Runloop

kCFRunLoopBeforeTimers = (1UL << 1),    //即将处理NSTimer

kCFRunLoopBeforeSources = (1UL << 2),   //即将处理Sources

kCFRunLoopBeforeWaiting = (1UL << 5),   //即将进入休眠

kCFRunLoopAfterWaiting = (1UL << 6),    //刚从休眠中唤醒

kCFRunLoopExit = (1UL << 7),            //即将退出runloop

kCFRunLoopAllActivities = 0x0FFFFFFFU   //所有状态改变

};

- 1.9 Runloop运行逻辑

-

![PNG](3.png)

--------------------

![PNG](4.png)

####2.Runloop应用

NSTimer

ImageView显示

PerformSelector

常驻线程

自动释放池

RunLoop笔记的更多相关文章

  1. ios之runloop笔记

    网上关于runloop的文章不计其数,再此,贴个自认为讲的比较简单明了的文章 http://www.jianshu.com/p/536184bfd163 个人理解: ios的runloop应该是类似于 ...

  2. 我的runloop学习笔记

    前言:公司项目终于忙的差不多了,最近比较闲,想起叶大说过的iOS面试三把刀,GCD.runtime.runloop,runtime之前已经总结过了,GCD在另一篇博客里也做了一些小总结,今天准备把ru ...

  3. RunLoop的简单理解笔记

    一句话解释RunLoop:运行任务的循环. 为什么要有RunLoop:解决交互式UI设计中的一个问题,如何快速响应用户输入,如何快速将程序运行结果输出到屏幕? 基本原理:1 将任务分解的足够细 2 每 ...

  4. 主线程 RunLoop 学习笔记

    以下为主RunLoop 的输出,能够看到不同的source0,source1,observer ---------------------------------- CFRunLoop{wakeup ...

  5. RAC学习笔记

    RAC学习笔记 ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾. 在学习Re ...

  6. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  7. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  8. IOS科研IOS开发笔记学习基础知识

    这篇文章是我的IOS学习笔记,他们是知识的基础,在这里,根据记录的查询后的条款. 1,UIScrollView能完毕滚动的功能. 示比例如以下: UIScrollView *tableScrollVi ...

  9. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

随机推荐

  1. Android studio下gradle Robolectric单元测试配置

    android studio下gradle Robolectric单元测试配置 1.Robolectric Robolectric是一个基于junit之上的单元测试框架.它并不依赖于Android提供 ...

  2. How threads differ from processes

    How threads differ from processes Threads differ from traditional multitasking operating system proc ...

  3. SAP LOGON DATA CHECK

    之前有朋友做过RFC登录验证,后来群里又有很多人问SAP的登录验证函数. 后来自己找找了,看看了,然后改写了一个LOGON DATA CHECK... FUNCTION ZUSER_CHECK_LOG ...

  4. T4模板批量生成代码

    大家通过比对下,就应该知道怎么玩. T4代码 <#@ template debug="false" hostspecific="true" languag ...

  5. mongodb-索引

    说明:创建索引时,列名:int 中的int数字指的是正序或者倒序,如果是1表明是正序,-1表示倒序 1.查询collection上的索引 db.users.getIndexes() 2.查询当前的db ...

  6. 测试一下Word发布刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了。

      刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了.   刚刚发现通过Word 可以直接发Blog 感觉很新奇,先看看,如果可以呢,将发通知的改了.     ...

  7. Leetcode 详解(股票交易日)(动态规划DP)

    问题描述: 在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行).给出一天中的股票变化序列,请写一个程序计算一天可以获得 ...

  8. LNAMP服务器环境搭建(手动编译安装)

    LNAMP服务器环境搭建(手动编译安装) 一.准备材料 阿里云主机一台,操作系统CentOS 6.5 64位 lnamp.zip包(包含搭建环境所需要的所有软件) http://123.56.144. ...

  9. 【资讯】天啦鲁,这十余款创客设计居然由FPGA搞定 [转]

    按理说‘高大上’的FPGA,多出现在航天航空(如火星探测器).通信(如基站.数据中心).测试测量等高端应用场景.但麦迪却也发现,近期,在很多创客的作品内部都有FPGA的影子.这或许也从侧面看出,打从总 ...

  10. 【JavaScript】固定布局轮播图特效

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...