Search code examples
iosswifttimerios9nstimer

Swift 3 precise Timer repeating (iOS 9)


I've got a precise timer that needs to be update every 40ms (most precisely than possible). On iOS10 it's good (I use the new scheduleRepeating method) but on iOS9 I need to use the old way (scheduledTimer) and it's pretty laggy (sometimes 24ms, sometimes its 72...), so my hardware interface and visual effects and lagging.

Any suggestion?

func launchTimer() {
    if #available(iOS 10.0, *) {
            startTickTimer()
    } else {
        let timerQueue =  DispatchQueue(label: "my.queue.tickTimer", attributes: .concurrent)
        self.swiftTimer = Timer.scheduledTimer(timeInterval: period, target: self, selector: #selector(executeTimer), userInfo: nil, repeats: true)
        timerQueue.async {
            RunLoop.current.add(self.swiftTimer!, forMode: RunLoopMode.defaultRunLoopMode)
        }
    }
}

static func startTickTimer() {
    let queue = DispatchQueue(label: "my.queue.tickTimer", attributes: .concurrent)
    DMXTimer.tickTimer?.cancel()
    DMXTimer.tickTimer = DispatchSource.makeTimerSource(queue: queue)
    DMXTimer.tickTimer?.scheduleRepeating(deadline: .now(), interval: .milliseconds(40), leeway: .seconds(1))
    DMXTimer.tickTimer?.setEventHandler {
        executeTimer()
    }
    DMXTimer.tickTimer?.resume()
}

static func executeTimer() {
    print("hello moto")
}

Solution

  • From Apple doc about NSTimer:

    A timer is not a real-time mechanism. If a timer’s firing time occurs during a long run loop callout or while the run loop is in a mode that isn't monitoring the timer, the timer doesn't fire until the next time the run loop checks the timer. Therefore, the actual time at which a timer fires can be significantly later. See also Timer Tolerance.

    If you want a very precise timer you can check an implementation from Apple Tech Note and adapt in Swift or use a CADisplayLink for display updates.