Swift - scheduledTimer stopwatch hours portion not working

笑着哭i 提交于 2019-12-12 04:08:40

问题


Bear with me I picked up Swift and Xcode a week ago (Im creating an app to learn Swift during my holidays)

I created a timer using scheduledTimer to act as an stopwatch. The seconds and minutes are running fine but I can't get the hours to work. What am I doing wrong?

currentTime = 0
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in

    self.currentTime += 1

    let hoursPortion = String(format: "%02d", CGFloat(self.currentTime) * 60)
    let minutesPortion = String(format: "%02d", self.currentTime / 60)
    let secondsPortion = String(format: "%02d", self.currentTime % 60)
    //let tenPortion = String(format: "%d", self.currentTime * 10 % 10)
    self.TimerDisplay.text = "\(hoursPortion):\(minutesPortion):\(secondsPortion)"
}

回答1:


As others have said, you shouldn't try to keep track of the time yourself. Let the system figure out how much time has elapsed. And, I'd be inclined to use DateComponentsFormatter to format the string for you, too:

@IBOutlet weak var elapsedLabel: UILabel!

weak var timer: Timer?

private var formatter: DateComponentsFormatter = {
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .positional
    formatter.allowedUnits = [.hour, .minute, .second]
    formatter.zeroFormattingBehavior = .pad
    return formatter
}()

private func startTimer() {
    timer?.invalidate()      // stop prior timer, if any

    let startTime = Date()

    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
        self?.elapsedLabel.text = self?.formatter.string(from: startTime, to: Date())
    }
}

deinit {
    timer?.invalidate()
}

BTW, it’s a subtle point, but please notice the use of [weak self] in the Timer closure’s capture list. In the absence of that, you have a variation of a strong reference cycle because timers don't stop until you invalidate them, but the view controller's deinit cannot be called until the timer's strong reference to the view controller is resolved. By using [weak self] capture list in the closure, we break that cycle, allowing the view controller to be deallocated when it's dismissed and it will stop the timer for you.




回答2:


This is not the best approach as the timer is not guaranteed to be accurate enough, it will drift over time. A better approach is to record a start time and use the calendar functions to give you the elapsed time. e.g.

        let startTime = Date()
        let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
            let now = Date()
            let components = Calendar.current.dateComponents([.hour, .minute, .second], from: startTime, to: now)

            guard let hoursPortion = components.hour, let minutesPortion = components.minute, let secondsPortion = components.second
            else {
                preconditionFailure("Should not happen")
            }

            self.TimerDisplay.text = "\(hoursPortion):\(minutesPortion):\(secondsPortion)"
        }


来源:https://stackoverflow.com/questions/44555604/swift-scheduledtimer-stopwatch-hours-portion-not-working

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!