深入理解RunLoop

深入理解RunLoop

本文主要根据苹果官方文档, 对RunLoop的概念进行解读,以及一些底层的实现原理,希望对深入理解RunLoop有帮助。

RunLoop的概念

官方解释:
Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.

其实可以这样理解, RunLoop是跟线程结合使用的, 我们都知道, 线程在执行完毕后就自动退出了, 这个线程的时间也就结束了, 如果我们想让这个线程不退出, 处于休眠状态, 随时可以接受我们的事件,那么应该怎么做呢?因此, 才引入了RunLoop的概念,目的就是为了让线程能够循环处理事件, 而且没有事件处理时处于休眠状态。

RunLoop并不是默认自动开启的, 一般我们应用的主线程会自动开启, 因为主线程需要随时处理跟UI相关的交互操作, 因此是自动开启RunLoop的, 而我们自己创建的线程一般是不自动开启的, 因此我们需要根据需求决定是否开启,那么什么情况系我们需要使用RunLoop呢?

一般是以下4种情况需要开启RunLoop:

1.Use ports or custom input sources to communicate with other threads.
2.Use timers on the thread.
3.Use any of the performSelector… methods in a Cocoa application.
4.Keep the thread around to perform periodic tasks.

看到这里, 其实我们可以发现, 线程间的通信其实就是通过RunLoop来实现的,至于具体怎么实现,本人还在进一步研究中。

RunLoop的结构

首先,先来看一张结构图:
这里写图片描述

从图中我们可以清楚地看出, 其实RunLoop就是一个死循环,
一直在接受 -> 处理 -> 等待的这样一个循环,可以看出RunLoop接受两种不同类型的sources, 一种是异步的的input sources, 另一种是同步的Timer sources,接下来会详细介绍RunLoop的各个结构。

RunLoop Modes

一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。

下面这种图就能够很清楚的解释mode和其他组件之间的关系,

这里写图片描述

下面官方文档给出的mode的类型:
这里写图片描述

其实我们经常使用的也就是:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。一种的默认的mode, 还有一种是跟滑动有关的mode。

这里有个概念叫 “CommonModes”:一个 Mode 可以将自己标记为”Common”属性(通过将其 ModeName 添加到 RunLoop 的 “commonModes” 中)。每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 “Common” 标记的所有Mode里。

应用场景举例:主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为”Common”属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。

有时你需要一个 Timer,在两个 Mode 中都能得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。还有一种方式,就是将 Timer 加入到顶层的 RunLoop 的 “commonModeItems” 中。”commonModeItems” 被 RunLoop 自动更新到所有具有”Common”属性的 Mode 里去。

Input Sources

官方文档给出的是以下几种input sources, Port-Based Sources,Custom Input Sources,Cocoa Perform Selector Sources,Timer Sources,Run Loop Observers 在之前的结构图中也可以看出来,同时这里也体现了RunLoop的使用场景。关于更多具体的介绍, 大家可以查阅官方文档。

这里介绍RunLoop内部的事件循环流程:
1. Notify observers that the run loop has been entered.
2. Notify observers that any ready timers are about to fire.
3. Notify observers that any input sources that are not port based are about to fire.
4. Fire any non-port-based input sources that are ready to fire.
5. If a port-based input source is ready and waiting to fire, process the event immediately. Go to step 9.
6. Notify observers that the thread is about to sleep.
7. Put the thread to sleep until one of the following events occurs:
An event arrives for a port-based input source.
A timer fires.
The timeout value set for the run loop expires.
The run loop is explicitly woken up.
8. Notify observers that the thread just woke up.
9. Process the pending event.
If a user-defined timer fired, process the timer event and restart the loop. Go to step 2.
If an input source fired, deliver the event.
If the run loop was explicitly woken up but has not yet timed out, restart the loop. Go to step 2.
10. Notify observers that the run loop has exited.

其实可以通过下面这张图来展现:

这里写图片描述

可以看到,实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。

总结

到这里, 关于RunLoop的一些基本概念就已经解释完了, 关于更多详细的解释, 大家可以查阅官方文档, 本人英语水平不高, 就不逐一翻译了。

参考:
深入理解RunLoop
Threading Programming Guide

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值