iOS开发RunLoop
最近处于离职状态,时间也多了起来,但是学习还是不能放松,今天总结一下RunLoop,RunLoop属于iOS系统层的东西,还是比较重要的。
一、什么是RunLoop
字面意思看是跑圈,也可以看作运行循环,我认为RunLoop是个强大的while循环,需要的时候可以将其唤醒工作,不需要的时候可以让其进行休眠节省资源。
那它又有什么作用呢,我总结主要有三点:(1)保持程序的持续运行(2)处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)(3)节省cpu资源,提高程序性能,该做事的时候做事,该休息的时候休息。举个例子,我们程序的入口main函数的UIApplicationMain函数内部久启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,保证了程序的持续运行,默认启动的RunLoop是跟我们主线程相关联的。
二、RunLoop对象
iOS提供了两套API来访问和使用RunLoop:
NSRunLoop(Foundation层)
CFRunLoopRef(Core Foundation层)
三、RunLoop与线程
(1)每条线程都有唯一的一个与之对应的RunLoop对象。
(2)主线程RunLoop已经是创建好的了,子线程的RunLoop需要主动创建。
(3)RunLoop在第一次获取时创建,在线程销毁时销毁,可以将其理解为线程中的变量。
四、RunLoop对象的获取方式
基于Foundation:
[NSRunLoop currentRunLoop];//或得当前线程的RunLoop对象
[NSRunLoop mainRunLoop];//获得主线程的RunLoop对象
基于Core Foundation:
CFRunLoopGetCurrent();//或得当前线程的RunLoop对象
CFRunLoopGetMain();//获得主线程的RunLoop对象
五、RunLoop相关类
Core Foundation中关于RunLoop的五个类:
(1)CFRunLoopRef
(2)CFRunLoopModeRef
(3)CFRunLoopSourceRef
(4)CFRunLoopTimerRef
(5)CFRunLoopObserverRef

RunLoop中可以有多个Mode,是RunLoop的重要组成部分,也是RunLoop中不可缺少的部分,可以理解为如果RunLoop中没有Mode那么RunLoop是跑不起来的。所以说它是不可缺少的部分。其中还包括Source,Timer,Observer。Timer是处理定时器的,Observer可以理解为对RunLoop的监听,不如RunLoop的开启或者休眠等等状态,Source表示所要处理的事情,比如说点击某个按钮处理一些事情都属于Source。我觉得有一点很重要,着重提一下,RunLoop的前提是有Mode,Mode的前提是有Source,Timer,Observer。
下面我们对RunLoop中的相关类做个详细介绍:
1.CFRunLoopModeRef
1.1 CFRunLoopModeRef
(1)CFRunLoopModeRef代表着RunLoop的运行模式。
(2)一个RunLoop包含若干个Mode,每个Mode又包含若干个Source,Timer,Observer。
(3)每次RunLoop启动时,只能指定其中一个Mode,这个Mode被称为CurrentMode。
(4)如果需要切换Mode,只能退出RunLoop,再重新指定一个Mode进入,这样做主要为乐分割Source,Timer,Observer让其互不影响。
1.2 系统会默认注册5个模式:
(1)kCFRunLoopDefaultMode:App默认的Mode,通常主线程是在这个Mode下运行的。
(2)UITrackingRunLoopMode:界面跟踪Mode,用于ScrollerView追踪触摸滑动,保证洁面滑动时不受其他Mode影响。
(3)UIInitializationRunLoopMode:在刚启动app时进入的第一个mode,启动完成后就不在使用。
(4)GSEventReceiveRunLoopMode:接受系统事件的内部mode,通常用不到。
(5)kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的mode,可以理解为不是一个确定的模式,既可以支持(1),又可以支持(2)。比如说我们在处理滑动事件定时器问题,这个mode就是很好的解决办法。
2.CFRunLoopSourceRef 事件源(输入源)
(1)Source0:非基于Port的,Port可以理解为我们的内核,比如说自定的一些事件,自己写的函数。
(2) Source1:基于Port的,相当于系统默认调的函数所产生的事件。
一个RunLoop的执行,在线程栈里会有一些我们看不到的函数是系统调用的。
3.CFRunLoopTimerRef
是基于时间的触发器,基本上说的就是NSTimer。
4.CFRunLoopObserverRef
CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变,可以监听的时间点有以下几个:
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry = (1UL << ),        //即将进入RunLoop
        kCFRunLoopBeforeTimers = (1UL << ), //即将处理Timer
        kCFRunLoopBeforeSources = (1UL << ),//即将处理Sources
        kCFRunLoopBeforeWaiting = (1UL << ),//即将进入休眠
        kCFRunLoopAfterWaiting = (1UL << ), //刚从休眠中唤醒
        kCFRunLoopExit = (1UL << ),         //即将退出RunLoop
        kCFRunLoopAllActivities = 0x0FFFFFFFU//监听RunLoop的所有情况
    };
比如我们想要在按钮点击之前或者点击之后去做一些事情,我们想要监听到这样的一个状态,就可以使用CFRunLoopObserverRef,NSRunLoop中并没有提供CFRunLoopObserverRef的相关接口,我们要使用只能在Core Foundation中使用。
下面通过实例监测下RunLoop的执行状态:
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, , ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"activity:%zd",activity);
    });
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
CFRelease(observer);
打印结果:
-- ::17.268 testRunloop[:] activity:
-- ::17.268 testRunloop[:] activity:
-- ::17.268 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.270 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.271 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.276 testRunloop[:] activity:
-- ::17.277 testRunloop[:] activity:
-- ::17.277 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.286 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.287 testRunloop[:] activity:
-- ::17.743 testRunloop[:] activity:
-- ::17.744 testRunloop[:] activity:
-- ::17.745 testRunloop[:] activity:
-- ::17.745 testRunloop[:] activity:
-- ::18.699 testRunloop[:] activity:
-- ::18.699 testRunloop[:] activity:
-- ::18.700 testRunloop[:] activity:
-- ::18.700 testRunloop[:] activity:
-- ::22.999 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:
-- ::23.000 testRunloop[:] activity:

现在看这张官方版的逻辑图是不是清晰多了,当然网友的力量是无尽的,下面再给大家展示张网友提供的逻辑图:

总结:RunLoop是与线程相对应的,每个线程都会有一个RunLoop,主线程的RunLoop默认是开启的,不需要我们处理,子线程的RunLoop是关闭的,需要我们自己开启,线程开启的时候RunLoop包含mode,而且必须在某个确定的模式下运行,mode里面的Source,Timer,Observer也需要有,还有包括它们所实现的功能等等。
以上就是对RunLoop的最基本的介绍,希望对大家的学习能有所帮助。
注:此文章为原创,转载请注明出处。
iOS开发RunLoop的更多相关文章
- iOS开发RunLoop学习:一:RunLoop简单介绍
		一:RunLoop的简单介绍 #import "ViewController.h" @interface ViewController () @end @implementatio ... 
- iOS开发RunLoop学习:四:RunLoop的应用和RunLoop的面试题
		一:RunLoop的应用 #import "ViewController.h" @interface ViewController () /** 注释 */ @property ( ... 
- iOS开发-Runloop详解(简书)
		不知道大家有没有想过这个问题,一个应用开始运行以后放在那里,如果不对它进行任何操作,这个应用就像静止了一样,不会自发的有任何动作发生,但是如果我们点击界面上的一个按钮,这个时候就会有对应的按钮响应事件 ... 
- iOS开发 - RunLoop理解
		RunLoop概念 运行循环,一个 run loop 就是一个事件处理的循环,用来不停的调度工作以及处理事件 作用 保持程序的持续运行 监听处理App中的各种事件(触摸事件,定时器事件,selecto ... 
- 玩转iOS开发 - Runloop 具体解释
		Runloop 具体解释 
- iOS开发RunLoop学习:三:Runloop相关类(source和Observer)
		一:RunLoop相关类: 其中:source0指的是非基于端口por,说白了也就是处理触摸事件,selector事件,source1指的是基于端口的port:是处理系统的一些事件 注意:创建一个Ru ... 
- iOS开发-- RunLoop的基本概念与例子分析
		看了一下,上一篇貌似5个月前的 
- iOS开发 - 啰嗦讲解 Runloop
		写在前面的 为什么要了解 RunLoop?如果你想成为一个高级iOS开发工程师,那这是你必须了解的东西,他能帮助你更好的理解底层实现的原理,可以利用它的特性做出一些高效又神奇的功能.RunLoop这个 ... 
- iOS开发 底层抛析运行循环—— RunLoop
		http://blog.csdn.net/zc639143029/article/details/50012527 一.RunLoop基本概念 概念:程序的运行循环,通俗的来说就是跑圈. 1. 基本作 ... 
随机推荐
- IOS解析XML
			XML也许是我们储存数据和通讯数据中最常见的一种简易方式,当我们来到XML的海洋时,我们会发现当我们用iPhone程序解析XML时,我们是有如此多的选项,让人眼花缭乱.iOS SDK本身就带有两种不同 ... 
- WinForm 制作一个简单的计算器
			namespace WindowsFormsApplication6 { public partial class Form1 : Form { //存储上次点击了什么按钮,0代表什么都没有点击,1代 ... 
- 蓝桥网试题 java 基础练习 时间转换
			--------------------------------------- --------------------------------------- import java.util.*; ... 
- Jenkins的新建job和配置job
			这里,我们说一下如何新建并且配置一个job,Jenkins的工作其实有很多都是靠job来完成的,job有很多的功能,这里我们只介绍如何新建和配置一个建构项目的job. 新建job 新 ... 
- 聊聊dmClock算法
			作者:吴香伟 发表于 2017/01/08 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 人们常常容易忽略一些不起眼但特别重要的事物.曾经跟同事聊Python, ... 
- 随机生成并排序 C,去同,有序数组合并排序
			#include<iostream> #include<stdlib.h> #include<time.h> using namespace std; int ma ... 
- BZOJ 3403: [Usaco2009 Open]Cow Line 直线上的牛(模拟)
			直接双端队列模拟,完了= = CODE: #include<cstdio>#include<algorithm>#include<iostream>#include ... 
- SQL中的存储过程和函数
			存储过程和函数 简单的说,存储过程就是一条或者多条SQL语句的集合.可以视为批文件,但是其作用不仅仅局限于批处理.本文主要介绍如 ... 
- angular drag and drop (ngDraggable) 笔记
			这是原文 https://github.com/fatlinesofcode/ngDraggable 这是另一个dnd,这比较灵活,可以监听事件.我只用简单的排序功能,其他没去了解太多.有机会遇到功能 ... 
- 从C#到TypeScript - Proxy
			总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ... 
