创建一个每秒运行一次的计时器,在第二个?

时间:2017-03-02 05:14:54

标签: ios timer nstimer

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

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

我在几个月前在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))
}

2 个答案:

答案 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)

在您的代码中,您在初始化组件时绝不会使用纳秒

因此计时器将始终以第二轮数字命中。

我在下面测试您的代码,在选择器enter image description here

中打印Date()

我不确定这是不是你在说什么&#34;命中零&#34;希望这会有所帮助