我有一个特定日期的倒数计时器。它看起来很不错,每秒更新一次以显示倒计时。这是我用来创建计时器的代码:
func scheduleTimeLabelsUpdateTimer() {
var components = Calendar.current.dateComponents([.day, .hour, .minute, .second], from: Date())
components.second! += 1
let nextSecondDate = Calendar.current.date(from: components)!
let timer = Timer(fireAt: nextSecondDate, interval: 1, target: self, selector: #selector(updateTimeLabels), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: .commonModes)
}
但是,我希望每秒更新,,以便时钟在每秒经过的同时更新。现在,它会在调用此方法时每秒更新一次,该方法位于viewDidLoad()
。
例如,如果倒计时设置为午夜,我希望它在午夜正好达到零。现在它可能会在午夜之后略微达到零,具体取决于用户打开此屏幕时的秒数。
编辑:这是向用户显示倒计时的方式。 updateTimeLabels()
只根据该日期之前剩余的时间设置每个标签的文本。我希望每一秒都能准确更新每个标签。这样倒计时将准确地“准时到零”。请注意现在如何,秒数达到零,然后状态栏上的系统时钟更新。我希望这些可以同时发生。
我在几个月前在Stack Overflow上找到的这段代码正在updateTimeLabels()
中调用以计算剩余时间:
public func timeOffset(from date: Date) -> (days: Int, hours: Int, minutes: Int, seconds: Int) {
// Number of seconds between times
var delta = Double(self.seconds(from: date))
// Calculate and subtract whole days
let days = floor(delta / 86400)
delta -= days * 86400
// Caluclate and subtract whole hours
let hours = floor(delta / 3600).truncatingRemainder(dividingBy: 24)
delta -= hours * 3600
// Calculate and subtract whole minutes
let minutes = floor(delta / 60.0).truncatingRemainder(dividingBy: 60)
delta -= minutes * 60
// What's left is seconds
let seconds = delta.truncatingRemainder(dividingBy: 60)
return (Int(days), Int(hours), Int(minutes), Int(seconds))
}
答案 0 :(得分:0)
由于在运行循环中安排了Timer
并且在运行循环中发生了其他事情,因此它并不特别准确;它将在指定的时间间隔之后触发,但在间隔过去时不一定完全
不要试图将计时器安排到所需的时间,而是应该以超过1秒的速度运行计时器,比如0.5秒,并在每次计时器触发时更新剩余时间标签。这样可以更顺畅地更新显示:
var timer: Timer?
func scheduleTimeLabelsUpdateTimer() {
self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (timer) in
self.updateTimeLabels()
}
}
<强>更新强>
不要做所有的数学运算; iOS内置了很好的库来为您完成所有这些工作;只需创建目标日期,然后使用DateComponents
为您完成目标。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var countDownLabel: UILabel!
let dateFormatter = DateFormatter()
var targetTime: Date!
var calendar = Calendar.current
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var components = DateComponents()
components.setValue(3, for: .month)
components.setValue(3, for: .day)
components.setValue(2017, for: .year)
components.setValue(0, for: .hour)
components.setValue(0, for: .minute)
components.setValue(1, for: .second)
self.targetTime = calendar.date(from: components)
self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { (timer) in
self.updateLabel()
})
self.dateFormatter.timeStyle = .long
self.dateFormatter.dateStyle = .short
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func updateLabel() {
let now = Date()
self.label.text = self.dateFormatter.string(from: now)
let components = calendar.dateComponents([.day,.hour,.minute,.second], from: now, to: self.targetTime)
self.countDownLabel.text = String(format: "%d days %d hours, %d minutes %d seconds", components.day!, components.hour!, components.minute!,components.second!)
}
}
答案 1 :(得分:0)