什么是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: NSRunLoop
Core 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在滑动时停止工作的问题
- 监控应用卡顿
- 性能优化