什么是 RunLoop
-
应用范畴
- 定时器、PerformSelector
- GCD Async Main Queue
- 事件响应、手势识别、界面刷新
- 网络请求
- AutoreleasePool
-
RunLoop的基本作用
- 保持程序的持续运行
- 处理 App 中的各种事件
- 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
RunLoop对象
NSRunLoop 是基于 CFRunLoopRef 的一层 OC 包装
RunLoop与线程
- 每条线程都有唯一的一个与之对应的 RunLoop对象
- RunLoop 保存在一个全局的 Dictionary里,线程作为 key,RunLoop 作为 value
- 线程刚创建时并没有 RunLoop对象,RunLoop 会在第一次获取它时创建
- RunLoop会在线程结束时销毁
- 主线程 RunLoop 自动获取,子线程默认没有开启 RunLoop(这个就是你在子线程只开启runloop他仍然会退出的原因)
RunLoop相关的类
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
}
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
}
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影响
RunLoop的运行逻辑
-
Source0
- 触摸事件处理
- performSelector:onThread:
-
Source1
- 基于 Port 的线程间通信
- 系统事件的捕捉
-
Timers
- NSTimer
- performSelector:withObject:afterDelay:
-
Observers
- 用于监听 RunLoop 的状态
- UI刷新(BeforeWaiting)
- AutoreleasePool(BeforeWaiting)
休眠的细节
用户态调用mach_msg(),就会切换到内核态去真正执行mach_msg(),让线程等待消息(没有消息让线程休眠,有消息就唤醒线程)
线程保活
[[NSRunLoop currentRunLoop] run]是无法停止的,它专门用于开启一个永不销毁的线程(NSRunLoop)