swift - 使用执行(afterDelay :) within a while loop gives me a logic error?

标签 swift loops delay

我正在制作一个计时器程序,它使用 slider 设置计时器值,然后更新数字时钟显示以将相应的剩余数字时间显示为图像文件。

我试图在 while 循环内运行 1 秒延迟函数,并每秒更新图像文件,本质上是尝试创建一个计时器,该计时器更新用于确定实时使用哪些图像的变量。

我很难正确分配倒计时:用于设置图像文件的变量 h , min1min2设置为0延迟 1 秒后。看起来 while 循环调用了一次延迟函数,迭代直到满足条件而不延迟计时器,然后显示最终值。

我尝试了不同的方法来计时 1 秒延迟,包括使用 let timer = Timer.方法和DispatchQueue.main.方法,但似乎不起作用。

    @IBAction func slider(_ sender: UISlider)
    {
        self.x = Int(sender.value)
        // Note I omitted the rest of this code as it concerned setting images while changing slider value, and used local variables.
    }

    var x: Int = 60
    var h: Int = 1
    var min1: Int = 1
    var min2: Int = 7

    @objc func animate2 ()
    {
        checkLbl.text = String(h) + ("1")
        checkLbl2.text = String(min1) + ("1")
        checkLbl3.text = String(min2) + ("1")
        self.H2ImageView.image = UIImage(named: "\(h).png")!
        self.M1ImageView.image = UIImage(named: "\(min1).png")!
        self.M2ImageView.image = UIImage(named: "\(min2).png")!
    }

    func animate ()
    {
        var timeLeft = x
        var seconds = 60
        while timeLeft >= 0
        {
            (h, _) = x.quotientAndRemainder(dividingBy: 60)
            (min1, min2) = x.quotientAndRemainder(dividingBy: 10)
            if min1 >= 6
            {
                min1 = min1 - 6
                if h == 2
                {
                    min1 = 0
                }
            }
            checkLbl.text = String(h)
            checkLbl2.text = String(min1)
            checkLbl3.text = String(min2)
            // checkLbl used to track the variables
            perform(#selector(animate2), with: nil, afterDelay: 1)
            seconds = seconds - 1
            if seconds == 0
            {
                timeLeft = timeLeft - 1
                seconds = 60
            }
        }
    }

    @IBAction func watchPress(_ sender: UIButton)
    {
        animate()
    }

总结一下:我预计延迟函数会更新h , min1min2 (因此更新 checkLbl 文本)每秒但是这些值直接进入 0 .

感谢任何帮助,谢谢!

最佳答案

您需要了解,performSelectorDispatchQueue.main.asyncAfterTimer 都在一定时间后异步运行代码。这意味着在此示例中,B 行不会在 A 行之后运行一秒:

checkLbl3.text = String(min2) // A
perform(#selector(animate2), with: nil, afterDelay: 1)
seconds = seconds - 1 // B

B 行将在 A 行之后立即运行。一秒钟后,animate2 将被调用。

因此,不应使用 while 循环。相反,您应该使用像这样的Timer:

Timer(timeInterval: 1, repeats: true) { (timer) in
    if timeLeft == 0 {
        timer.invalidate()
    }
    seconds -= 1
    if seconds == 0
    {
        timeLeft = timeLeft - 1
        seconds = 60
    }
    // update the labels and image views
}

我还建议您仅将剩余时间存储为秒数。删除 hmin1min2seconds 变量。仅从更新 UI 时剩余的时间开始计算它们。

关于swift - 使用执行(afterDelay :) within a while loop gives me a logic error?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55569227/

相关文章:

database - Swift 代码在变量设置期间结束

swift - UIView 的 AirPrint 内容

jQuery 回调函数仅在最后一个循环中触发

javascript - 在数组对象中查找字符串值的最简洁方法?

php - 如何让 sleep 函数在 PHP 的 for 循环中做出适当响应

ios - 如何杀死 Vapor 服务器

c# - 如何通过速记 "if-else"结果打破循环?

Jquery 滑动每次点击都会有更多延迟

c# - 调用 Task.Delay() 并在几分钟后询问还剩多少时间

ios - 传递 "partial closure"的优雅方式?