-
什么是RunLoop?
-
从字面上来看是运行循环的意思.
-
内部就是一个do{}while循环,在这个循环里内部不断的处理各类任务(好比:source/timer/Observer)
-
RunLoop的存在其实就是为线程而存在的.线程的做用就是执行一个特定的任务,可是默认状况下线程执行完任务后就不能再次执行任务,这是由于默认状况下线程是没有开启RunLoop的.若是开启RunLoop以后,线程执行完任务以后,会一直等待,直到再次接受到任务,接续执行任务.线程销毁前,会先释放这个线程所对应的RunLoop.
-
RunLoop基本做用
-
保持程序的持续运行,保持线程的持续运行.
-
处理App中的各类事件(好比触摸事件,定时器事件,Selector事件)
-
节省CPU资源,提升程序性能:该作事时作事,该休息时休息
-
RunLoop对象
-
ios中有2套API来访问和使用RunLoop
-
一套是Fundation(纯OC的)框架中的
-
一套是Core Fundation(纯C语言的)框架中的
-
NSRunLoo和CFRunLoopRef都表明着RunLoop对象.NSRunLoop是基于CFRunLoopRef的一层OC包装
-
RunLoop与线程
-
每条线程都有惟一的一个与之对应的RunLoop对象
-
主线程的Runloop系统已经自动建立好了,子线程的RunLoop须要手动建立
-
RunLoop在第一次获取时由系统自动建立,在线程结束时销毁
-
若是想给子线程建立RunLoop,不能直接alloc&init,只要调用获取当前线程RunLoop方法便可,系统会自动放回当前线程的RunLoop,若是当前线程没有RunLoop,系统会自动建立.
-
RunLoop相关类
-
Core Fundation中关于RunLoop的5个类
-
CFRunLoopRef: RunLoop对象
-
CFRunLoopModeRef: RunLoop运行模式.
-
CFRunLoopSoruceRef: 事件源(输入源)
-
CFRunLoopTimerRef:基于时间的触发器.
-
CFRunLoopObserverRef: 观察者,可以监听RunLoop的状态改变
-
CFRunLoopModeRef
-
CFRunLoopModeRef表明RunLoop运行模式
-
一个RunLoop对象包含若干个Mode(模式),每一个Mode又包含若干个 source/Timer/Observer
-
RunLoop运行时,只能指定一个Mode, 这个Mode又称之为CurrentMode,而后RunLoo就执行CurrentMode中的source/Timer/Observer
-
若是须要切换Mode,只能退出RunLoop,再从新指定一个Mode进入,这样作是为了分隔开不一样组的Source/Timer/Observer,让其不受影响
-
系统默认注册了5个Mode:
-
NSDefaultRunLoopMode: App的默认Mode,一般主线程实在这个模式下运行
-
UITrackingRunLoopMode:界面跟踪Mode,用于界面控件(ScrollView,tableView等等)追踪触摸滑动,保证界面滑动时不受其余Mode影响
-
UIInitializationRunLoopMode:在刚启动App是进入的第一个Mode,启动完成后就再也不使用
-
GSEventReceiveRunLoopMode:接收系统事件的内部Mode,一般用不到
-
NSRunLoopCommonMode:这是一个占位的Mode,不是一种真正的Mode,(能够当作模式组,默认状况下包括了NSDefaultRunLoopMode,UITrackingRunLoopMode)两种模式.
-
CFRunLoopTimerRef
-
CFRunLoopSoruceRef
-
按照官方文档,source的分类:
-
Port-Based Sources:基于端口的事件源:监听程序响应的端口,基于端口事件是由系统内核自动发送的.
-
Custom Input Sources: 自定义输入源:监听自定义事件源,而自定义的输入源是须要人工从其余线程发送
-
Cocoa Perfrom Selector Source: selector事件源
-
按照源码函数调用栈,source的分类:
-
Source0:非基于Prot(端口)的,是用户主动触发的事件
-
Source1:基于Prot(端口)的,经过内核和其余线程相互发送消息
-
CFRunLoopObserverRef
-
RunLoop处理逻辑
-
若是RunLoop中没有Timer或source,RunLoop就会马上退出
-
每次运行RunLoop,RunLoop会自动处理以前未处理的消息,并通知相关观察者.具体顺序以下:
-
1.通知观察者RunLoop已经启动
-
2.通知观察者即将开始启动定时器
-
3.通知观察者即将启动非基于端口的事件源
-
4.启动任何准备好的非基于端口的事件源
-
5.若是基于端口的事件源准备好并处于等待得状态,当即启动.并进入步骤9
-
6.通知观察者线程进入休眠
-
7.将线程置于休眠直到任意下面的事件发生:
-
某一事件到达基于端口的源
-
定时器启动
-
RunLoop设置的时间已经超时.(系统底层会给RunLoop设置一个超时时间,源码中设置的是:9999999999.0)
-
RunLoop被手动唤醒
-
8.通知观察者线程将被唤醒.
-
9.处理未处理的事件
-
若是用户定义的定时器启动,处理定时器事件并重启RunLoop.进入步骤2
-
若是事件源启动,传递相应的消息
-
若是RunLooop被显示唤醒并且时间还没超时,重启RunLoop.进入步骤2
-
10.通知观察者RunLoop结束.
-
如何让子线程成为常驻线程(让一个子线程不进入消亡状态,等待其余线程发来消息,处理其余事件)
原文连接:http://www.jianshu.com/p/94d61de9e139