0. 前言
RunLoop
详解的文章很多,其实大都来源于那么一两篇,本篇就不再赘述,相关文章会在文末标出。
把相关知识整理成了一张图,看起来也方便一点。
直接看理论可能不太好理解,那么就跟着先来简单感受一下RunLoop
吧!
1. 感受 RunLoop
简单地说,RunLoop 就是一个 do-while 循环,反复处理事件。
1.1 RunLoop何时出现?
在 main 函数和 appdelegate 内打断点,观察何时出现 runloop
打印结果:
main 函数开始
RunLoopMode: kCFRunLoopDefaultMode
<CFRunLoop 0x6000001f4700 [0x10e6c7c80]> {......}
复制代码
我们发现:
1.没有打印“main 函数结束”;
2.app 启动后出现了 runloop
这是因为在 app 启动过程中,app 会自动在主线程创建并运行 runloop,循环使 app 得以持续运行,所以 main 不会 return。
1.2 窥探 runloop 的结构
上面 ?的打印结果中<CFRunLoop 0x6000001f4700 [0x10e6c7c80]> {...}
括号内可以看到主线程 runloop 的大致结构, 我们可以由此观察到 runloop 的结构。
打印结果精简如下:
CFRunLoop {
current mode = kCFRunLoopDefaultMode,
common modes = {
UITrackingRunLoopMode
kCFRunLoopDefaultMode
},
common mode items ={
// sources0 (manual)
CFRunLoopSource { order = -2, callout = __handleHIDEventFetcherDrain}
CFRunLoopSource { order = -1, callout = __handleEventQueue}
CFRunLoopSource { order = -1, callout = PurpleEventSignalCallback}
CFRunLoopSource { order = 0, callout = FBSSerialQueueRunLoopSourceHandler}
// sources1 (mach port)
CFRunLoopSource { order = 0, port = 14107}
CFRunLoopSource { order = 0, port = 41987}
CFRunLoopSource { order = -1, callout = PurpleEventCallback}
// observers
CFRunLoopObserver { order = -2147483647, activities = 0x1, callout = _wrapRunLoopWithAutoreleasePoolHandler}
CFRunLoopObserver { order = 0, activities = 0x20, callout = _UIGestureRecognizerUpdateObserver}
CFRunLoopObserver { order = 1999000, activities = 0xa0, callout = _beforeCACommitHandler}
CFRunLoopObserver { order = 2000000, activities = 0xa0, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv}
CFRunLoopObserver { order = 2001000, activities = 0xa0, callout = _afterCACommitHandler}
CFRunLoopObserver { order = 2147483647, activities = 0xa0, callout = _wrapRunLoopWithAutoreleasePoolHandler}
// activities: 0x1 == Entry ; 0x20 == BeforeWaiting ; 0xa0 == BeforeWaiting | Exit
}
,
modes = {
UITrackingRunLoopMode {
sources0 = {/* 同 common mode items 内的 source0 */}
sources1 = {/* 同 common mode items 内的 source1 */}
observers = {/* 同 common mode items 内的 observers */}
timers = (null),
}
GSEventReceiveRunLoopMode {
sources0 = {CFRunLoopSource { order = -1, callout = PurpleEventSignalCallback}}
sources1 = {CFRunLoopSource { order = -1, callout = PurpleEventCallback}}
observers = (null),
timers = (null),
}
kCFRunLoopDefaultMode {
sources0 = {/* 同 common mode items 内的 source0 */}
sources1 = {/* 同 common mode items 内的 source1 */}
observers = {/* 同 common mode items 内的 observers */}
timers = {CFRunLoopTimer {firing = No, interval = 0, tolerance = 0, next fire date = 552971546 (-10.567408 @ 89128060961915), callout = (Delayed Perform) UIApplication _accessibilitySetUpQuickSpeak (UIKit.framework/UIKit)}}
}
kCFRunLoopCommonModes {
sources0 = (null),
sources1 = (null),
observers = (null),
timers = (null),
}
}
}
复制代码
可以看到,主线程的 runloop 当前处于kCFRunLoopDefaultMode
,注册了四种modes
。
结合上面和源码可以精简出线程的 runloop 大致结构:
struct __CFRunLoop {
CFMutableSetRef _commonModes;// 具有'common'属性的 modes
CFMutableSetRef _commonModeItems;// 同步到'common'modes的 items
CFRunLoopModeRef _currentMode;// 当前 runloop 所处的 mode
CFMutableSetRef _modes;// runloop 注册的 modes
...
};
复制代码
贴张大神的图以便理解:
- 一条线程对应一个
runloop
- 一个
runloop
含有多个mode
- 一个
mode
内可以含有多个soucre
、timer
和observer
1.3 runloop 在 app 静止时在干嘛?
静止时,点暂停:
发现在没有事件处理时,线程的runloop
都停留在mach_msg_trap
状态, 等待事件发生。(像是布了个陷阱,等待猎物上钩,一上钩就立马处理)
2. 一张图就够了
3. 实践代码
有空再补吧...