user
user

Reputation: 455

Swiftui - Timer drifting over a period of time

I have a workout timer that lets the user workout for 30 seconds & then break for 10 seconds. I have some visual aspects that represent this with some Text saying whether it's a break or a workout time. When the timer first starts it works good, but over time it drifts off & the text begins to be changed early then it should. I'm invalidating my timers once they are done, I can't see why I would be getting different results just because time has passed.

func start() {
    centreText = "Workout"
    Timer.scheduledTimer(withTimeInterval: 30, repeats: false) { timer in
        timer.invalidate()
        break()
    }
    
}

func break() {
    breatheText = "Break"
    Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { timer in
        timer.invalidate()
        start()
    }
}

How I'm calling start:

.onAppear {
  withAnimation(.workout(workDuration: 30, break: 10), {
  start()
 })

Workout Animation:

public static func workout(workDuration: Double, break: Double) -> Animation {
    return Animation.easeInOut(duration: workDuration).delay(break).repeatForever(autoreverses: true)
}

Upvotes: 0

Views: 211

Answers (1)

Cuneyt
Cuneyt

Reputation: 991

As views in SwiftUI are structs, it's best to use a configurator class using ObservableObject to update UI. Handle all the timers in this class and use a Published variable that the view assigns to.

struct MyView: View {

  @StateObject private var config = MyViewConfig()
  
  var body: some View {
    Text(config.message)
    Button("Start", action: config.start)
  }
}

private final class MyViewConfig: ObservableObject {

  @Published private(set) var message = "Workout"

  func start() {
    // star timer and update message
    message = "Workout"
  }
  
  func stop() {
    // stop timer and update message
    message = "Break"
  }
}

Upvotes: 2

Related Questions