忍受我一周前我选择了Swift和Xcode(我在假期期间创建了一个学习Swift的应用程序)
我使用scheduledTimer创建了一个计时器作为秒表。秒和分钟运行正常,但我无法让时间工作。我做错了什么?
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)"
}
答案 0 :(得分:1)
正如其他人所说,你不应该试图自己跟踪时间。让系统计算出已经过了多长时间。并且,我倾向于使用DateComponentsFormatter
为您格式化字符串:
@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()
}
顺便说一句,这是一个微妙的观点,但请注意在[weak self]
闭包的捕获列表中使用Timer
。如果没有这个,你有一个强大的参考周期的变化,因为定时器不会停止,直到你invalidate
,但视图控制器的deinit
无法被调用,直到定时器的强引用视图控制器已解决。通过在闭包中使用[weak self]
捕获列表,我们打破了该循环,允许视图控制器在被解除时被释放,并且它将为您停止计时器。
答案 1 :(得分:0)
这不是最好的方法,因为定时器不能保证足够准确,它会随着时间的推移而漂移。更好的方法是记录开始时间并使用日历功能为您提供已用时间。例如
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)"
}