数字电路:五分钟计时器_井字游戏:它是什么计时器?

数字电路:五分钟计时器

Hi everybody, I’m Riccardo. Senior iOS Engineer at Bending Spoons, I breathe iOS development, both apps and tools and I love to share my knowledge with others

大家好,我是Riccardo。 Bending Spoons的高级iOS工程师,我负责iOS开发,包括应用程序和工具,我喜欢与他人分享我的知识

Sooner or later, we need to write some code that involves timers. Displaying a count-down? You may need a timer. Showing a continuous animation in discrete steps? You may need a timer. Performing an operation every x seconds? You’ll probably need a timer.

迟早,我们需要编写一些涉及计时器的代码。 显示倒数? 您可能需要一个计时器。 在不连续的步骤中显示连续的动画? 您可能需要一个计时器。 每x秒执行一次操作? 您可能需要一个计时器。

Apple offers different options for timers, every one with its own features. The main ones are:

Apple为计时器提供了不同的选项,每个选项都有自己的功能。 主要的是:

  • Timer: a general-purpose timer.

    Timer :通用计时器。

  • CADisplayLink: a timer whose firing rate is bound to the screen refresh rate.

    CADisplayLink :一个计时器,其触发频率与屏幕刷新率绑定。

  • DispatchSourceTimer: a versatile timer that monitors the time events of the OS.

    DispatchSourceTimer :多功能计时器,用于监视操作系统的时间事件。

计时器 (Timer)

The first and the most common option: the classic Timer.

第一个也是最常见的选择:经典Timer

Why is this so common? It is easy to create it and run it, and it offers some methods to customize it. A typical code to schedule a recurring timer looks like this:

为什么这么常见? 创建和运行它很容易,并且它提供了一些自定义它的方法。 安排循环计时器的典型代码如下:

The returned object offers some interesting methods and properties:

返回的对象提供了一些有趣的方法和属性:

  1. fire()to force it to fire immediately.

    fire()强制其立即射击。

  2. invalidate() to stop it.

    invalidate()停止它。

  3. fireDate property to check when it will fire again.

    fireDate属性以检查何时会再次触发。

  4. tolerance to set a tolerance for the next firing time.

    tolerance设置下一次点火时间的容差。

It looks like this timer provides everything we need! But what limitations does it have?

看来此计时器提供了我们所需的一切! 但是它有什么限制?

If the UI is performing complex operations, like scrolling a collection view with big images, the timer will fire with an unpredictable delay. The fire interval will not be respected! From the documentation:

如果UI正在执行复杂的操作(例如,滚动带有大图像的收藏夹视图),则计时器将以不可预测的延迟触发。 开火间隔将不予遵守! 从文档中:

A timer is not a real-time mechanism. If a timer’s firing time occurs during a long run loop callout or while the run loop is in a mode that isn’t monitoring the timer, the timer doesn’t fire until the next time the run loop checks the timer. Therefore, the actual time at which a timer fires can be significantly later.

计时器不是实时机制。 如果计时器的触发时间发生在长时间运行的循环调用期间或运行循环处于不监视计时器的模式下,则直到下次运行循环检查计时器时,计时器才会启动。 因此,计时器触发的实际时间可能要晚得多。

It has another shortcoming: if scheduled from a secondary thread, it won’t fire. A Timer attach itself to the RunLoop associated with the thread from where it is scheduled. By default, secondary thread in iOS does not have a RunLoop and it’s the developer's responsibility to create and manage it.

它还有另一个缺点:如果从辅助线程进行调度,则不会触发。 Timer将自己附加到与RunLoop线程相关联的RunLoop 。 默认情况下,iOS中的辅助线程没有RunLoop ,创建和管理它是开发人员的责任。

So, which other tools do we have to address these issues?

那么,我们还必须解决哪些其他工具?

CADisplayLink (CADisplayLink)

The perfect tool for a precise ticking is the CADisplayLink.

CADisplayLink是精确滴答的完美工具。

This object comes from the CoreAnimation framework and it is extremely precise because it is invoked every time the screen is refreshed. The screen refresh rate should always be at 60 frames per second: so it is invoked 60 times every second.

该对象来自CoreAnimation框架,它非常精确,因为每次刷新屏幕时都会调用该对象。 屏幕刷新率应始终为每秒60帧:因此,每秒刷新60次。

The typical code to schedule a display link looks like the following:

安排显示链接的典型代码如下所示:

For the CADisplayLink to work as we want, we need to perform some additional operations:

为了使CADisplayLink能够按需要工作,我们需要执行一些其他操作:

  1. We need to attach it manually to a run loop. Otherwise, the timer will be created but it won’t fire.

    我们需要将其手动附加到运行循环。 否则,将创建计时器,但不会触发。
  2. We need to perform a bit of simple math. The display link will fire 60 times every second and, in general, we don’t have to execute its callback that often. The difference between the displayLink.timestamp and the lastTick is used to execute the callback every time interval we need.

    我们需要执行一些简单的数学运算。 显示链接每秒将触发60次,通常,我们不必经常执行其回调。 displayLink.timestamplastTick之间的差异用于在我们需要的每个时间间隔执行回调。

The display link offers the same invalidate method of the Timer to stop it.

显示链接提供了与Timer相同的invalidate Timer停止的方法。

However, also CADisplayLink won’t fire when it’s started in the background.

但是, CADisplayLink在后台启动时也不会触发。

DispatchSourceTimer (DispatchSourceTimer)

The last tool I’d like to talk about is the DispatchSourceTimer. This is quite a rare timer that uses a DispatchSource to monitor the time events of the OS.

我想谈的最后一个工具是DispatchSourceTimer 。 这是一个非常罕见的计时器,它使用DispatchSource监视操作系统的时间事件。

The code to schedule this timer looks like this:

安排此计时器的代码如下所示:

Like in the CADisplayLink case, the DispatchSourceTimer requires a bit of setup:

像在CADisplayLink一样, DispatchSourceTimer需要一些设置:

  1. We need to create the timer. We can pass a flag, in the example above .strict, and the queue in which it will be executed. This is the trick to have it working in a background thread.

    我们需要创建计时器。 在上面的示例中,我们可以传递一个标志.strict ,并在其中执行该标志。 这是使它在后台线程中工作的技巧。

  2. set up a handler to do the work we need every time it fires.

    设置handler来执行每次触发时我们需要的工作。

  3. use the schedule(deadline:, repeating:, leeway:) method to define the first execution, the repeated executions, and an eventual tolerance

    使用schedule(deadline:, repeating:, leeway:)方法定义第一次执行,重复执行以及最终的容忍度

  4. invoke resume() to actually start it.

    调用resume()实际启动它。

There is another tricky detail about DispatchSourceTimer: we have to maintain a strong reference to it. In the case of Timer and CADisplayLink, it is the RunLoop in which they are executed that retains their references. That’s not the case for the DispatchSourceTimer and it’s our responsibility to keep it alive.

关于DispatchSourceTimer还有另一个棘手的细节:我们必须对其进行严格的引用。 对于TimerCADisplayLink ,将在其中执行它们的RunLoop保留其引用。 DispatchSourceTimer并非如此,保持它的生命是我们的责任。

When do we need such a timer? For example, when we want to send measurements to a server at some specific intervals without weighing too much on the system’s resources.

我们什么时候需要这样的计时器? 例如,当我们希望以特定的时间间隔将测量结果发送到服务器而又不会过多地占用系统资源时。

结论 (Conclusion)

Running a timer looks like a trivial matter but that’s not always the case. Apple offers several tools to face the challenges of a repeated task and, as usual, the more we know the better we can tackle our problems.

运行计时器看起来很简单,但并非总是如此。 Apple提供了多种工具来应对重复任务的挑战,并且像往常一样,我们知道的越多,就能越好地解决问题。

The Timer class is the most general and the simplest one. It is the first that we should try to use, especially if we don’t have any special needs. If we do, however, we can consider one of the other tools: if we have to be extremely precise, we can go with the CADisplayLink; if we need to run the timer from a secondary thread, we can use the DispatchSourceTimer.

Timer类是最通用和最简单的类。 这是我们应该尝试使用的第一个方法,特别是如果我们没有任何特殊需要时。 但是,如果这样做,我们可以考虑使用其他工具之一:如果必须非常精确,则可以使用CADisplayLink 。 如果需要从辅助线程运行计时器,则可以使用DispatchSourceTimer

Try always to choose the right tool for the right job!

始终尝试为正确的工作选择正确的工具!

翻译自: https://medium.com/swlh/tic-toc-what-timer-is-it-2200458c86f5

数字电路:五分钟计时器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值