什么是RunLoop
顾名思义,RunLoop就是运行循环,在程序运行过程中循环做一些事情。在iOS系统中RunLoop有以下应用场景:
- 定时器、PerformSelector
 - CGD Async Main Queue
 - 事件响应、手势识别、界面刷新
 - 网络请求
 - AutoreleasePool
 
试想以下如果程序没有RunLoop会怎样?
1  | int main(int argc, const char * argv[]){  | 
执行完打印语句该程序就会退出运行。
那么如果有了RunLoop呢?我们看下面的代码
1  | int main(int argc, char *argv[]){  | 
这是一个APP程序的main函数,这个函数启动后APP是不会自动退出的,这是为什么呢?原因就是 UIApplicationMain 函数里面有运行循环,大致的原理跟下面的代码类似:
1  | int main(int argc, char *argv[]){  | 
那么通过上面的分析我们发现RunLoop的基本作用应该是:
- 保持程序的持续运行
 - 处理App中的各种事件(比如触摸事件、定时器事件等)
 - 节省CPU资源,提高程序性能:该做事的时候做事,该休息的时候休息
 - ……
 
RunLoop对象
iOS中有两套API来访问和使用RunLoop
Foundation: NSRunLoopCore Foundation: CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象
- NSRunLoop是基于CFRunLoopRef的一层OC包装
 - CFRunLoopRef是开源的:https://opensource.apple.com/tarballs/CF/
 

RunLoop与线程
- 每条线程都有唯一的一个与之对应的
RunLoop对象 RunLoop保存在一个全局的Dictionary里,线程为Key,RunLoop作为value- 线程刚创建的时候没有
RunLoop对象,RunLoop会在第一次获取它时创建 RunLoop会在线程结束是销毁- 主线程的
RunLoop已经自动获取(创建),子线程默认没有开启RunLoop 
获取RunLoop对象
1  | Foundation  | 
RunLoop相关的类
CoreFoundation中关于RunLoop的5个类
- CFRunLoopRef
 - CFRunLoopModeRef
 - CFRunLoopSourceRef
 - CFRunLoopTimerRef
 - CFRunLoopObserverRef
 
1  | typedef struct __CFRunLoop *CFRunLoopRef;  | 
1  | typedef struct __CFRunLoopMode *CFRunLoopModeRef;  | 

CFRunLoopModeRef
CFRunLoopModeRef代表RunLoop的运行模式;
一个RunLoop包含若干个Mode,每个Mode又包含若干个Source0/Source1/Timer/Observer;
RunLoop启动时只能选择其中一个Mode,作为currentMode
如果切换Mode,只能退出当前Loop,再重新选择一个Mode进入,不同组的Source0/Source1/Timer/Observer能分隔开来,互不影响
如果Mode里没有任何Source0/Source1/Timer/Observer,RunLoop会立马退出
常见的两种Mode:
- kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程在这个Mode下运行
 - UITrackingRunLoopMode: 界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
 
CFRunLoopObserverRef
1  | typedef CF_OPTIONS(CFOptionFlags,CFRunLoopActivity){  | 
添加Observer监听RunLoop的所有状态
1  | CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopAllActivities,YES,0,^void(CFRunLoopObserverRef observer,CFRunLoopActivity activity){  | 
RunLoop的运行逻辑

Source0
- 触摸事件处理
 - performSelector:onThread:
 
Source1
- 基于Port的线程间通信
 - 系统事件捕捉
 
Timer
- NSTimer
 - performSelector:withObject:afterDelay:
 
Observers
- 用于监听RunLoop的状态
 - UI刷新(BeforeWaiting)
 - AutoReleasePool(BeforeWaiting)
 
运行流程介绍:

RunLoop休眠的实现原理

RunLoop在实际开发中的应用场景
- 控制线程的声明周期(线程保活)
 - 解决NSTimer在滑动时停止工作的问题
 - 监控应用卡顿
 - 性能优化