标签显示倒计时有时会在暂停后不同步。舍入错误?

问题描述 投票:0回答:1

我有一个使用Timer进行倒计时的应用。倒计时会跟踪多个步骤(所有时间间隔相同)以及剩余的总时间,并相应地更新2个单独的UILabel。有时,标签将不同步。

我不能肯定地说,但我认为这可能仅在我暂停倒计时时才会发生,通常是在第一步之后。在最后一步中,最明显的是两个标签应该显示相同的确切内容,但有时会相差1秒。

另一个棘手的事情是,有时在时间不同步后暂停并重新开始会使其恢复同步。

我的猜测是我在暂停代码和/或步骤之间的移动中发生了一些奇怪的事情,或者可能是TimeIntervals的计算和格式化。另外,我在计算出的TimeIntervals上使用rounded(),因为我注意到仅每1秒更新一次计时器,标签将冻结并跳过很多秒。但是我不确定这是否是解决此问题的最佳方法。

这里是相关代码。 (仍然需要进行重构,但希望它很容易理解,我仍然是初学者)

@IBAction func playPauseTapped(_ sender: Any) {
        if timerState == .running {
            //pause timer
            pauseAnimation()
            timer.invalidate()
            timerState = .paused
            pausedTime = Date()
            playPauseButton.setImage(UIImage(systemName: "play.circle"), for: .normal)
        } else if timerState == .paused {
            //resume paused timer
            guard let pause = pausedTime else { return }
            let pausedInterval = Date().timeIntervalSince(pause)
            startTime = startTime?.addingTimeInterval(pausedInterval)
            endTime = endTime?.addingTimeInterval(pausedInterval)
            currentStepEndTime = currentStepEndTime?.addingTimeInterval(pausedInterval)
            pausedTime = nil
            startTimer()
            resumeAnimation()
            timerState = .running
            playPauseButton.setImage(UIImage(systemName: "pause.circle"), for: .normal)
        } else {
            //first run of brand new timer
            startTimer()
            startProgressBar()
            startTime = Date()
            if let totalTime = totalTime {
                endTime = startTime?.addingTimeInterval(totalTime)
            }
            currentStepEndTime = Date().addingTimeInterval(recipeInterval)
            timerState = .running
            playPauseButton.setImage(UIImage(systemName: "pause.circle"), for: .normal)

            currentWater += recipeWater[recipeIndex]
            currentWeightLabel.text = "\(currentWater)g"
        }
    }

func startTimer() {
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(runTimer), userInfo: nil, repeats: true)
    }

@objc func runTimer() {
        let currentTime = Date()

        guard let totalTimeLeft = endTime?.timeIntervalSince(currentTime).rounded() else { return }

        guard let currentInterval = currentStepEndTime?.timeIntervalSince(currentTime).rounded() else { return }

        //end of current step
        if currentInterval <= 0 {
            //check if end of recipe
            if recipeIndex < recipeWater.count - 1 {
                //move to next step
                totalTimeLabel.text = totalTimeLeft.stringFromTimeInterval()
                currentStepEndTime = Date().addingTimeInterval(recipeInterval)
                startProgressBar()
                currentStepTimeLabel.text = recipeInterval.stringFromTimeInterval()
                stepsTime += recipeInterval
                recipeIndex += 1
                //update some ui
            } else {
                //last step
                currentStepTimeLabel.text = "00:00"
                totalTimeLabel.text = "00:00"
                timer.invalidate()
                //alert controller saying finished
            }
        } else {
            //update time labels
            currentStepTimeLabel.text = currentInterval.stringFromTimeInterval()
            totalTimeLabel.text = totalTimeLeft.stringFromTimeInterval()
        }

    }

extension TimeInterval {

    func stringFromTimeInterval() -> String {

        let time = NSInteger(self)

        let seconds = time % 60
        let minutes = (time / 60) % 60

        return String(format: "%0.2d:%0.2d",minutes,seconds)

    }
}

编辑更新:我尝试了一些不同的操作,但仍然遇到相同的问题。我开始测试打印TimeInterval和格式化的字符串,以进行比较并查看发生了什么。肯定是某种舍入错误。

Total - 173.50678288936615 / 02:54
Step - 39.00026595592499 / 00:39
Total - 172.5073879957199 / 02:53
Step - 38.00087106227875 / 00:38
Total - 171.1903439760208 / 02:51
Step - 36.68382704257965 / 00:37
Total - 170.19031596183777 / 02:50
Step - 35.683799028396606 / 00:36

如您所见,总时间从2:53跳到2:51,但是步进计时器保持一致。原因是TimeInterval总计从172.5(向上舍入)到171.19(向下舍入)。

我还看着计时器倒计时而没有碰到暂停,它可靠地保持同步。因此,我将其范围缩小到我的暂停代码。

ios swift timer uilabel
1个回答
0
投票

已解决我的问题,并在此处张贴以供后代参考。我最终完成了totalTimeLeftcurrentInterval全局属性。然后,在暂停和恢复时,我没有使用已暂停的时间并将其添加到endTime,而是仅使用了从上次totalTimeLeft触发并执行currentInterval时仍然存储的TimerendTime = Date().addingTimeInterval(totalTimeLeft)值与间隔时间相同。这消除了暂停时间所增加的奇怪数量,而这些数量会弄乱四舍五入。

© www.soinside.com 2019 - 2024. All rights reserved.