RunLoop 介绍
运行循环,在程序运行过程中循环做一些事情,如果没有 Runloop 程序执行完毕就会立即退出,如果有Runloop程序会一直运行,并且时时刻刻在等待用户的输入操作。RunLoop 可以在需要的时候自己跑起来运行,在没有操作的时候就停下来休息。充分节省 CPU 资源,提高程序性能。
1、RunLoop 的基本作用
- 保持程序的持续运行
- 处理 App 中的各种事件(比如触摸事件、定时器事件等)
- 节省 CPU 资源,提高程序性能:该做事时做事,该休息时休息
2、RunLoop 对象
iOS 中有 2 套 API 来访问和使用 RunLoop
Foundation:NSRunLoop
Core Foundation:CFRunLoopRef
NSRunLoop 和 CFRunLoopRef 都代表着 RunLoop 对象
NSRunLoop 是基于 CFRunLoopRef 的一层 OC 包装
CFRunLoopRef 是开源的
3、RunLoop 与线程
- 每条线程都有唯一的一个与之对应的 RunLoop 对象
- RunLoop 保存在一个全局的 Dictionary 里,线程作为 key,RunLoop 作为 value
- 线程刚创建时并没有 RunLoop 对象,RunLoop 会在第一次获取它时创建
- RunLoop 会在线程结束时销毁
- 主线程的 RunLoop 已经自动获取(创建),子线程默认没有开启 RunLoop
4、获取RunLoop对象
1 | // Foundation |
5、RunLoop 相关的类
Core Foundation 中关于 RunLoop 的5个类
- CFRunLoopRef
1 | typedef struct __CFRunLoop * CFRunLoopRef |
- CFRunLoopModeRef
1 | typedef struct __CFRunLoopMode * CFRunLoopModeRef |
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
6、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 会立马退出
- 系统默认注册了 5 个 Mode
- kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App 的默认 Mode,通常主线程是在这个 Mode 下运行的
- UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
- UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
- GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
- kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用
7、RunLoop的运行逻辑
Source0
- 触摸事件处理
- performSelector:onThread:
Source1
- 基于 Port 的线程间通信
- 系统事件捕捉
Timers
- NSTimer
- performSelector:withObject:afterDelay:
Observers
- 用于监听 RunLoop 的状态
- UI刷新(BeforeWaiting)
- Autorelease pool(BeforeWaiting)
7、RunLoop在实际开中的应用
- 控制线程生命周期(线程保活)
- 解决NSTimer在滑动时停止工作的问题
- 监控应用卡顿
- 性能优化