0

I have a question regarding timers and publishers. I'm working with a timer that fires every second and does a small calculation and an update of two published values for counting down in the UI.

I've put everything that is not UI related on background threads and when the timer only runs the background code the interval is fine at 1.000 with some tolerance. But when the timer is also updating the two published values on the main thread the interval is between 1.015 and 1.019.

That doesnt sound much but after 20 minutes the total offset is at about 20 seconds.

Is there a best practice or a solution for that?

View:

@EnvironmentObject var timer: TimerData
let counter = Timer.publish(every: 1.0, tolerance: 0.2, on: .main, in: .common).autoconnect()

...

.onReceive(counter) { _ in
    DispatchQueue.global(qos: .userInteractive).async {
        timer.countingTime()
    }
}

Model:

class TimerData: ObservableObject {

@AppStorage("time") var time: Int = 0
@AppStorage("lastAction") var lastAction: Double = 0

func countingTime() {
    let now = Double(NSDate().timeIntervalSince1970)
    let diff = Int(round(now - self.lastAction))

    print(now - self.lastAction)

    DispatchQueue.main.async {
        self.lastAction = now
        self.time -= diff
    }
}
}

I've tried no tolerance value when creating the timer as well as a higher tolerance value. The only way I found to get the interval to the estimated 1.000 is to make "time" and "lastAction" not published (@AppStorage or @Published didnt made a difference). But I need both values published (I guess).

Lars
  • 63
  • 1
  • 3
  • Timers are not very precise. You could try this: https://stackoverflow.com/a/43746977/6950415. Or redesign everything to a single source of truth in a Date format and make your calculations from there. – burnsi Apr 23 '22 at 09:20
  • I don't need high precision. A small tolerance is okay as long as the average is 1.000 and not 1.015. I think that I will calculate the time as a Double and round it when displaying the seconds. That would result in a 2 second jump once a minute or I'll fire the timer more often. Maybe every 0.2 seconds and round the time then. – Lars Apr 23 '22 at 10:43

0 Answers0