【问题标题】:Resetting DispatchQueue each time a tap occurs每次点击时重置 DispatchQueue
【发布时间】:2020-02-12 17:42:30
【问题描述】:

我有一个简单的应用程序,旨在像这样工作:

  • 使用默认图片加载应用
  • 一旦收到点击,就会从列表中加载随机图像
  • 如果 5 秒内未收到任何点击,我们将重置为默认图像

我正在尝试使用 DispatchQueue 和 DispatchWorkItem 来完成此任务。我已经设法使上述功能正常工作 - 除非用户多次点击

我假设这是因为我们每次点击时都会启动“resetToOff”DispatchWorkItem 而没有重置 5 秒。

如果在重置 DispatchQueue 时 5 秒内没有收到触摸,如何将图像重置为默认图像?

这是我目前所拥有的:

import SwiftUI



struct PlayView : View {
@ObservedObject var viewRouter: ViewRouter
@State var imageName : String = "smiley"

var body: some View {

    ZStack {
        Color.black
        .edgesIgnoringSafeArea(.all)

        Image(imageName)
    }

    .gesture(
        TapGesture()
            .onEnded {
                let resetToOff = DispatchWorkItem {
                    self.imageName = "smiley"
                }

                self.changeImage()

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5), execute: resetToOff)
            }
    )
    // Activate the options menu
    .onLongPressGesture(minimumDuration: 3) {
            self.viewRouter.currentPage = "menuView"
    }
 }

 func changeImage() {
    let tempImageName : String = self.imageName

        let list : Array = [
            "smileyPink",
            "smileyGreen",
            "smileyRed",
            "smileyBlue",
            "smileyYellow"
        ]

        self.imageName = list.randomElement() ?? ""
 // Ensure that new image selection is not the same as previous image
        while tempImageName == self.imageName {
            self.imageName = list.randomElement() ?? ""
            }
    }
 }

    struct PlayView_Previews : PreviewProvider {
    static var previews: some View {
        PlayView(viewRouter: ViewRouter())
    }
}

对此的任何帮助将不胜感激。

【问题讨论】:

    标签: ios swift iphone swiftui dispatch-queue


    【解决方案1】:

    使用 Timer 会更简单,因为如果用户在 Timer 在 5 秒结束时触发之前点击,它很容易取消 (invalidate) 并再次启动计时器 (Timer.scheduledTimer) .

    例如,这就是我的 LinkSame 应用程序的工作方式。有一个 10 秒的“移动”计时器。如果用户在前一次移动的 10 秒内没有做出有效移动,用户将失去 10 分,计时器重新开始。如果用户确实在前一次移动的 10 秒内做出了有效移动,则用户会根据我们在计时器中的位置获得分数,并且计时器会重新开始。这一切都是通过计时器完成的。

    【讨论】:

      【解决方案2】:

      我认为修改你的代码真的很容易,这样resetToOff 只会在 last 点按 5 秒或更长时间后执行某些操作:

      var lastTapped: DispatchTime
      ...
      
      .gesture(
          TapGesture()
              .onEnded {
                   lastTapped = DispatchTime.now() // remember the time of last tap
      

      然后:

      let resetToOff = DispatchWorkItem {
                      if self.lastTapped + .seconds(5) <= DispatchTime.now() { // 5 sec passed from last tap
                          self.imageName = "smiley"
                      } // otherwise do nothing
                  }
      

      由于设置和修改lastTapped 都发生在主线程上,因此它是线程安全的。当然,这意味着您可能会在主队列中添加“无需工作”项目,但这可能影响非常小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-08
        • 2014-11-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多