RunLoop 一张图就够了

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内可以含有多个soucretimerobserver

1.3 runloop 在 app 静止时在干嘛?

静止时,点暂停:

发现在没有事件处理时,线程的runloop都停留在mach_msg_trap状态, 等待事件发生。(像是布了个陷阱,等待猎物上钩,一上钩就立马处理)


2. 一张图就够了

3. 实践代码

有空再补吧...

参考:
源码
官方文档 Run Loops
深入理解RunLoop
iOS线下分享《RunLoop》

转载于:https://juejin.im/post/5b4564876fb9a04fb4014b7b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值