I'm working on an app where I'm using a timer to count down time left in a workout and also count up for total time. My counters are out of sync, looks like it's less than a second off. I'm wondering if it has something to do with @Publish, maybe one fires before the other. Any idea what's happening and how to fix it?
class TimeManager: ObservableObject {
@Published var totalTime: Double = 0.0
@Published var timeRemaining: Double = 180.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() 2.0) {
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] timer in
guard let self = self else { return }
self.timeRemaining -= 0.1
self.totalTime = 0.1
}
}
}
then my view
@ObservedObject var timeManager = TimeManager()
...
var body: some View {
VStack {
let time = timeManager.timeRemaining
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
ZStack {
Progress()
Text(String(format:"i:i", minutes, seconds))
.font(.system(size: 60))
}
let total = timeManager.totalTime
let totalMins = Int(total) / 60 % 60
let totalSecs = Int(total) % 60
Text(String(format:"i:i", totalMins, totalSecs))
.font(.system(size: 40))
}
}
CodePudding user response:
Maybe calculate your 2nd value based on the first when you decrement the time. For example like this: remaining = (180 - total) >= 0 ? (180 - total) : 0
CodePudding user response:
Your time values are in sync. The reason for the behaviour you are seeing is the Double
/ Int
conversions and the rounding applied while display the Text
s. Try this line:
Text("\(timeManager.timeRemaining timeManager.totalTime)")
and you will see this allways adding up to 180.
You could try Int values in your Viewmodel decrementing/incrementing by 1 and a DateComponentsFormatter
to format the values in your View.
let componentsFormatter = DateComponentsFormatter()
Text("\(componentsFormatter.string(from: Double(timeManager.timeRemaining)) ?? "NAN")")
.font(.system(size: 60))
You would of course need to tweek the formatter to display the time the way you want it to be. But I agree with Paulw11. This seems like a bad design. It would be better to have a single source of truth as a Date
and go from there.