2017-03-02 168 views
2

我有一个倒数计时器到一个特定的日期。它看起来不错,每秒更新一次以显示倒计时。下面是我用来创建计时器代码:创建一个计时器,每秒钟运行一次?

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()只是根据在该日期之前剩余的时间量设置每个标签的文本。我希望每一个标签都能在每一秒完全更新。这样倒计时将准确地按时“打零”。注意现在如何,秒数达到零,然后状态栏上的系统时钟更新。我希望这些发生在同一时间。

enter image description here

此代码,这是我几个月前发现某处的堆栈溢出,被称为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

倒数计时器显示特定日期之前的天数,小时数,分钟数和秒数。如果日期设定为今晚午夜,那么我希望所有这些标签在今晚变成午夜时都准确地说出“0”,而不是一秒钟之后的一部分。 – CompC

+0

它现在的行为如何? –

回答

0

由于Timer被安排在运行循环其他事情正在运行循环中发生,这并不是特别准确;它会在经过指定的时间间隔后激发,但当间隔已过时,不一定恰好为

而不是试图为所需的时间安排计时器,你应该运行你的计时器超过1秒,比如说0.5秒,并且每当定时器触发时更新你的剩余时间标签。这将使一个平滑的更新显示:

var timer: Timer? 

func scheduleTimeLabelsUpdateTimer() { 

self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (timer) in 
     self.updateTimeLabels() 
    } 
} 

UPDATE

不要做这些数学; 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!) 

    } 


} 
+0

这似乎并不奏效......它仍然和以前一样。 – CompC

+0

你能展示更多代码吗?你如何追踪剩余时间?你如何更新标签?你究竟看到了什么? – Paulw11

+0

我在原帖中增加了更多细节。要更新标签,我正在计算剩余时间,然后在每个标签上设置文本。 – CompC

0

在你的代码,你当你初始化你的组件

所以定时器将总是打在轮第二个数字永远不会使用纳秒。

我测试下方打印Date()你的代码中选择enter image description here

我不知道这是否是你所谈论的“打零”是什么,希望这将有助于