每次点击时重置 DispatchQueue

Resetting DispatchQueue each time a tap occurs

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

我正在尝试使用 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())
    }
}

如有任何帮助,我们将不胜感激。

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

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

我认为修改您的代码非常容易,这样 resetToOff 仅在从 last tap:

过去 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 都发生在主线程上,因此它是线程安全的。当然,这意味着您可能会将 "no work needed" 项目添加到主队列,但这可能影响很小。