Search code examples
swiftconcurrencytimer

Swift Timer not working properly for old iPhone models


I am getting a problem with Swift timer. Timer are not working properly for old iPhone models like iPhone 6. When I printed out time, timer counts every 2 second as 1 second. But if i change withTimeInterval as 0.05, it works a bit better. But still is not work as real life time. Here is my code. Can anyone help me ?

weak var timer: Timer?
var startTime : TimeInterval!
var elapsingTime: Double = 0.0

func configureTimer(totalSecond: Double) {

    startTime = Date().timeIntervalSinceReferenceDate
    self.invalidateTimer()

    DispatchQueue.main.async {
        self.timer = Timer.scheduledTimer(timeInterval: 0.02,target: self,selector: #selector(self.advanceTimer(timer:)),userInfo: nil,repeats: true)

    }

}

@objc func advanceTimer(timer: Timer) {

    elapsingTime += 0.02

    self.questionView.configureProgressBar(totalTime: Double(self.totalSecond), elapsingTime: elapsingTime)
    self.isTimeExpired = false

    self.elapsingTime = Date().timeIntervalSinceReferenceDate - self.startTime

    if Int(elapsingTime) == Int(totalSecond) {

        self.timer!.invalidate()
        self.isTimeExpired = true
        self.userAnswerIndex = -1
        self.sendAnswer(index: self.userAnswerIndex, isTimeExpired: self.isTimeExpired)
    }
}

Solution

  • Timers are not very precise. There precisions is about 0.05 seconds I think. And if a process require a lot of power, your timer will be even more slowed down. The solution can be to save the time when you start your timer and that each time your timer fire, you do a mathematical operation to know how many time passed :

    class YourClass {
    
    var startTime : TimeInterval!
    
    //...
    
    func configureTimer() {
        startTime = Date().timeIntervalSinceReferenceDate //You add this line
    
        elapsingTime = 0.0
        timer?.invalidate()
    
        DispatchQueue.main.async {
    
            self.timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { [weak self] timer in
    
                guard let self = self else { return }
    
                self.elapsingTime = Date().timeIntervalSinceReferenceDate - self.startTime //You change this one
                self.questionView.configureProgressBar(totalTime: self.totalTime, elapsingTime: self.elapsingTime)
                self.questionView.videoQuestionPlayer.player?.play()
                if Int(self.elapsingTime) == Int(self.totalTime) {
    
                    self.timer!.invalidate()
                    self.isTimeExpired = true
                    self.sendAnswer(index: -1)
                }
            })
        }
    }
    

    }