OC内存管理-runloop

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OC内存管理-runloop相关的知识,希望对你有一定的参考价值。

参考技术A

RunLoop 是通过内部维护的 事件循环( Event Loop ) 来对 事件/消息 进行管理的一个对象。

runloop 的官方文档在 thread 篇章 Run Loops ,也就从侧面说明了 runloop 是与线程息息相关的。

官方有如下一张图:

线程的输入源:

线程针对输入源的处理机制:

有以下案例:

timer 与 performSelector 对应的回调都是 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ :

block 对应 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ :

主线程对应 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ :

系统触摸事件对应 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ :

通知事件对应 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ :

小结:

滚动页面输出:

页面滚动过程中处于 UITrackingRunLoopMode ,静止状态处于 kCFRunLoopDefaultMode 。

输出:

输出:

既然 runloop 是一个事件循环,那么它与普通的循环有什么区别呢?
普通循环:

runloop 循环:

那么可以得到以下结论:

那么 runloop 是怎么做到的呢?
通常我们会通过 NSRunLoop 去获取当前的 runloop :

定义如下:

给 currentRunLoop 下符号断点:

通过之前的分析已经定位到了 runloop 是在 CoreFoundation 中的 CoreFoundation源码 。正好 CoreFoundation 开源了 CFRunLoop :

那么核心逻辑就在 CFRunLoopRunSpecific 中。还有一个疑问是 runloop 可以休眠,那么它是如何实现的呢?

要了解 runloop 的实现原理,首先要清楚它的数据结构。

CFRunLoopRunSpecific 的第一个参数是 CFRunLoopGetCurrent() :

_CFRunLoopGet0

CFRunLoopRef 的定义如下:

实际上底层它是 __CFRunLoop 类型:

对于 timer 而言:

显然它是要依赖 mode 的。

CFRunLoopMode

而一个 mode 下又对应多个 items(source0、source1、timers、observers) ,所以就有如下关系:

既然有多种 mode ,那么都有哪些呢?
源码中有如下定义:

它们对应 Foundation 中的:

我们都清楚在页面滚动的时候有一个 UITrackingRunLoopMode :

除了以上 3 种 mode 还有两个私有 mode :

当 RunLoop 运行在 Mode1 上时,是无法接受处理 Mode2 或 Mode3 上的 Source、Timer、Observer 事件的。

以 timer 为例,将 timer 加入到 runloop 中:

底层调用了 CFRunLoopAddTimer :

根据要加入的 mode 区分是 common mode 和非 common mode 将 timer 加入 mode 中。这个时候只是将 timer 加入了 mode 中,要执行肯定要调用 CFRunLoopRun ,最终要调用 CFRunLoopRunSpecific 。

在 __CFRunLoopRun 中调用了 __CFRunLoopDoTimers :

找到 mode 中的所有 timer 然后调用 __CFRunLoopDoTimer 。

CFRunLoopAddTimer -> CFRunLoopRunSpecific -> __CFRunLoopRun -> __CFRunLoopDoTimers -> __CFRunLoopDoTimer -> __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__

与 timer 相同 source 会调用 CFRunLoopAddSource :

CFRunLoopAddSource -> CFRunLoopRunSpecific -> __CFRunLoopRun -> __CFRunLoopDoSources0/__CFRunLoopDoSources1 -> __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ /__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__

同理 observer 会调用 CFRunLoopAddObserver 。

以上是关于OC内存管理-runloop的主要内容,如果未能解决你的问题,请参考以下文章

iOS OC08,09_内存管理

OC 内存管理:MRC与ARC

OC基础--OC内存管理原则和简单实例

OC内存管理-ARC

OC内存管理

OC内存管理