美文网首页SwiftUI
SwiftUI:使用计时器重复触发事件

SwiftUI:使用计时器重复触发事件

作者: 韦弦Zhy | 来源:发表于2020-10-15 19:14 被阅读0次

\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

{\Large \mathbf{Flashzilla}}

iOS带有内置的Timer类,使我们可以定期运行代码。它使用来自 Apple 框架称为 Combine 的发布者系统。实际上,在本系列的许多应用中,我们实际上一直在使用 Combine 的一部分,尽管您不太可能会注意到它。例如,@Published属性包装器和ObservableObject协议都来自 Combine,但是我们不需要知道,因为当您导入SwiftUI时,我们也会隐式地导入 Combine 的一部分。

Apple 的核心系统库称为 Foundation,它为我们提供了诸如 DataDateNSSortDescriptorUserDefaults之类的功能。它还为我们提供了Timer类,该类旨在在一定的秒数后运行函数,但它也可以重复运行代码。Combine 对此添加了扩展,以便计时器可以成为发布者,这些发布者会在其值更改时宣布。这是@Published属性包装器的名称来源,计时器发布者以相同的方式工作:到达您的时间间隔时,Combine 将发出包含当前日期和时间的公告。

创建计时器发布者的代码如下所示:

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

它一次性做了这几件事:

  1. 它要求计时器每1秒触发一次。
  2. 它说计时器应该在主线程上运行。
  3. 它说计时器应该在 Common Mode Run Loop 中运行,这是您大部分时间要使用的循环。(这个类型的 Run Loop 使 iOS 在用户积极执行某项操作(例如滚动列表)时可以处理运行中的代码。)
  4. 它会立即连接计时器,这意味着它将开始计时。
  5. 它将整个事物分配给timer常量,以便它保持活动状态。

如果您还记得的话,在项目7中我曾说过“@Published大约是@State的一半” ——它发送变更公告,其他人可以监视。对于像这样的常规发布者,我们需要使用名为onReceive()的新修饰符来手动捕获公告。这将接受发布者作为其第一个参数,并接受要作为其第二个函数运行的函数,并且它将确保在发布者发送其更改通知时都会调用该函数。

对于我们的计时器示例,我们可以收到如下通知:

Text("Hello, World!")
    .onReceive(timer) { time in
        print("The time is now \(time)")
    }

这将每秒打印一次时间,直到计时器最终停止。

说到停止计时器,需要花一点时间才能停止我们创建的计时器。您会看到,我们制作的timer属性是一个自动连接的发布者,因此我们需要转到其上游发布者来查找计时器本身。从那里我们可以连接到计时器发布者,并要求它取消自身。老实说,如果不是为了完成代码,这将很难找到,但是它在代码中的外观如下:

self.timer.upstream.connect().cancel()

例如,我们可以更新现有示例,以使其仅触发计时器五次,如下所示:

struct ContentView: View {
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @State private var counter = 0

    var body: some View {
        Text("Hello, World!")
            .onReceive(timer) { time in
                if self.counter == 5 {
                    self.timer.upstream.connect().cancel()
                } else {
                    print("The time is now \(time)")
                }

                self.counter += 1
            }
    }
}

在结束之前,我想向您展示一个更重要的计时器概念:如果您对计时器有一点浮动感到满意,则可以指定一些公差。这使iOS可以执行重要的耗能优化,因为iOS可以在其计划的启动时间与计划的启动时间加您指定的容差之间的任何时间触发计时器。实际上,这意味着系统可以执行计时器合并:它可以将计时器稍微向后推,以便与一个或多个其他计时器同时触发,这意味着它可以使CPU保持更多的空闲时间并节省电池电量。

例如,这为我们的计时器增加了半秒的容限:

let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()

如果您需要严格保持时间,那么不使用公差(tolerance)参数将使您的计时器尽可能准确,但是请注意,即使没有任何公差,Timer类也仍然是“尽力而为”的做法——系统无法保证它将准确执行。

译者注:
Common Modes 不是一种真正的RunLoop Mode,是一种伪模式,指可以在标记为Common Modes的 RunLoop 模式下运行

目前被标记为 Common Modes 的模式: kCFRunLoopDefaultModeUITrackingRunLoopMode

所以类似 Timer 添加到 Common Mode 的时候,并不是真正的添加了,他查找他的modes, 然后给他的modes 添加 Timer即实际上,Timer 添加到了 Default 和 Tracking模式。

译自 Triggering events repeatedly using a timer

相关文章

  • SwiftUI:使用计时器重复触发事件

    iOS带有内置的Timer类,使我们可以定期运行代码。它使用来自 Apple 框架称为 Combine 的发布者系...

  • 干货!Swift/OC一个倒计时.计时器

    计时器案例场景:短信验证码、商品抢购倒计时……实现目标: 使用方便,高内聚低耦合高度模块化 不重复触发,重复触发不...

  • 服务器开发中对于计时器的处理

    简介 游戏服务器开发过程中经常会需要使用计时器来触发相应的事件,这篇文章主要是将什么时候需要使用计时器,什么不是不...

  • JS debounce(防抖) 和 throttle(节流)

    防抖 防抖,即如果短时间内大量触发同一事件,都会重置计时器,等到事件不触发了,再等待规定的时间,才会执行函数。* ...

  • js 文本框 (input)禁止输入

    先简单说明下键盘事件: keydown事件按下键盘上的任意键触发;按住不放,重复触发。 keypress事件按下键...

  • animator

    Any State:当前执行的状态 动画事件触发: 用计时器触发 配置文件:读写txt1.动画名字2.动画的路径3...

  • Event Bus 在Vue中的使用

    使用on全局监听 使用$emit触发事件。

  • bootstrap中下拉菜单(dropdown)的问题

    通过行间触发事件: 通过jQuery触发事件: 当使用方法去触发时,其中dropdown('toggle')和想象...

  • 解决jquery重复触发事件

    由于事件重复绑定了,所以会重复触发事件解决方法:第一种、通过unbind先解绑,然后再绑定事件第二种、通过$._d...

  • js逻辑运算

    1.使用JS触发事件(dispatchEvent) 例如:主动触发click事件 var event=new Ev...

网友评论

    本文标题:SwiftUI:使用计时器重复触发事件

    本文链接:https://www.haomeiwen.com/subject/xceppktx.html