- 版权声明:本文为博主原创文章,未经博主允许不得转载。
一. Runloop的基本知识
1. 概念
Runloop是运动循环,不断跑圈,无限循环.
RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理。之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池、延迟回调、触摸事件、屏幕刷新等功能的。
- 作用:
保持程序的持续运行 (iOS程序一直活着的原因)
处理App中的各种事件(eg:触摸事件/定时器事件/selector事件[选择器·performSelector···])
节省CPU资源,提高程序的性能(有事做事,没事休息)
程序已启动,就开启了一个runloop无限循环,因此程序才能持续的运行
2.RunLoop对象
- 在iOS开发中有两套api来访问Runloop
Foundation框架 [NSRunloop](OC)
Core Foundation框架 [CFRunloopRef](C)```
2. NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换
3. NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
######3.Runloop与线程的关系
1.Runloop和线程的关系:一个Runloop对应着一条唯一的线程
问题:如何让子线程不死
回答:给这条子线程开启一个Runloop
2.Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建
3.Runloop的生命周期:在第一次获取时创建,在线程结束时销毁
###二. Runloop对象的创建
1. Foundation框架\[NSRunloop]创建Runloop对象
// 获取当前线程下的Runloop, 懒加载的形式创建
NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
// 获取主线程下的Runloop
NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];```
- Core Foundation框架[CFRunloopRef]创建Runloop对象
// 获取当前线程下的Runloop, 懒加载的形式创建
CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
// 获取主线程下的Runloop
CFRunLoopRef runloop2 = CFRunLoopGetMain();```
3. Runloop运行原理图
![图片来自官网](http://upload-images.jianshu.io/upload_images/838345-faae7ec4a5fb10db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4.Runloop相关的类
CFRunLoopRef
CFRunloopModeRef [Runloop的运行模式]
CFRunloopSourceRef [Runloop要处理的事件源]
CFRunloopTimerRef [Timer事件]
CFRunloopObserverRef [Runloop的观察者(监听者)]```
Runloop要想跑起来,它的内部必须要有一个mode,mode中必须有source/observer/time,至少要有其中的一个.
5.CFRunloopModeRef [Runloop的五个运行模式]
Runloop每次启动的时候只能指定一个运行模型,切换模式时必须退出当前的Runloop,再重新进入一个mode,是为了分割不同组的定时器互不影响
kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
6.CFRunloopTimerRef [Timer事件]
-
1.Timer事件
- 2.GCD定时器
GCD定时器必须必须保存起来才能使用
- (void)gcdTimer
{
NSLog(@"+++++++++");
// 1.创建定时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
// 2.设置定时器
/*
第一个参数:定时器
第二个参数:从哪个时间开始
第三个参数:间隔时间
第四个参数:精确度, 0代表无误差
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
// 3.定时器触发事件
dispatch_source_set_event_handler(timer, ^{
NSLog(@"----------");
});
// 4.开启定时器
dispatch_resume(timer);
// GCD定时器创建是个局部变量需要保存才能执行
self.timer = timer;
}```
- 3.CFRunloopSourceRef [Runloop要处理的事件源]
(1)以前的分法
```swift
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources```
(2)现在的分法
```swift
Source0:非基于Port的 (用户触发的时间)
Source1:基于Port的 (通过内核和其它线程相互发送消息)```
- 4.CFRunloopObserverRef [Runloop的观察者 (监听者)]
![](http://upload-images.jianshu.io/upload_images/838345-f15d99e192b2398a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注意:
![](http://upload-images.jianshu.io/upload_images/838345-5ed898f1141c64c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 5.Runloop运行逻辑
![](http://upload-images.jianshu.io/upload_images/838345-0e9a4fa01684f71d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/838345-a917e5bd50943a4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###iOS中的RunLoop
>Runloop是事件接收和分发机制的一个实现。
Runloop提供了一种异步执行代码的机制,不能并行执行任务。
在主队列中,Main RunLoop直接配合任务的执行,负责处理UI事件、定时器以及其他内核相关事件。
>RunLoop的主要目的:
保证程序执行的线程不会被系统终止。
>什么时候使用RunLoop ?
当需要和该线程进行交互的时候才会使用Runloop.
每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。
一般情况下我们是没有必要去启用线程的RunLoop的,除非你在一个单独的线程中需要长久的检测某个事件。
主线程��默认有Runloop。当自己启动一个线程,如果只是用于处理单一的事件,则该线程在执行完之后就退出了。所以当我们需要让该线程监听某项事务时,就得让线程一直不退出,runloop就是这么一个循环,没有事件的时候,一直卡着,有事件来临了,执行其对应的函数。
Runloop,正如其名所示,是线程进入和被线程用来响应事件以及调用事件处理函数的地方。需要在代码中使用控制语句实现run loop的循环,也就是说,需要代码提供while 或者 for循环来驱动run loop。
在这个循环中,使用一个Runloop对象[NSRunloop currentRunloop]执行接收消息,调用对应的处理函数。
Runloop接收两种源事件:input sources和timer sources。
input sources 传递异步事件,通常是来自其他线程和不同的程序中的消息;
timer sources(定时器) 传递同步事件(重复执行或者在特定时间上触发)。
除了处理input sources,Runloop 也会产生一些关于本身行为的notificaiton。注册成为Runloop的observer,可以接收到这些notification,做一些额外的处理。(使用CoreFoundation来成为runloop的observer)。
>Runloop工作的特点:
1> 当有事件发生时,Runloop会根据具体的事件类型通知应用程序作出响应;
2> 当没有事件发生时,Runloop会进入休眠状态,从而达到省电的目的;
3> 当事件再次发生时,Runloop会被重新唤醒,处理事件。
>提示:一般在开发中很少会主动创建Runloop,而通常会把事件添加到Runloop中。
####参考:
[官方文档](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW47)
[深入理解RunLoop](http://blog.ibireme.com/2015/05/18/runloop/)