I'm currently prototyping a timer app in Swift Playgrounds.
The code for the top-level view and the child view is the following:
import SwiftUI
import Foundation
import PlaygroundSupport
struct MultiTimerView: View {
@State private var timerList = [TimerManager]()
var body: some View {
VStack(spacing: 20){
ForEach(timerList.indices, id: \.self) { id in
SingleTimerView(timerManager: self.$timerList[id])
}
Spacer()
Button(action:addTimer){
Image(systemName:"plus")
}
}
}
func addTimer(){
timerList.append(TimerManager())
}
}
struct SingleTimerView: View {
@Binding var timerManager : TimerManager
var body: some View {
HStack(spacing: 20){
Spacer()
Stepper("\(timerManager.secondsLeft)", value: $timerManager.secondsLeft, in: 0...1000)
Spacer()
Button(action:self.timerManager.toggleTimer){
Image( systemName: self.timerManager.timerRunning ? "pause.fill" : "play.fill")
}
Spacer()
}
}
}
PlaygroundPage.current.setLiveView(MultiTimerView().padding(50))
The code for the TimerManager class is the following:
import SwiftUI
import Foundation
import PlaygroundSupport
public class TimerManager: ObservableObject,Identifiable{
@Published public var timerRunning = false
@Published public var secondsLeft = 0
var timer = Timer()
public var id = UUID()
public init() {}
public func toggleTimer(){
if timerRunning == false {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true , block: { timer in
if self.secondsLeft == 0 {
self.timerRunning = false
self.secondsLeft = 0
timer.invalidate()
} else {
self.secondsLeft-=1
}
})
} else {
timer.invalidate()
}
timerRunning.toggle()
}
}
The bug happens doing the following:
create a timer with the + button
load the timer a given amount of seconds with its stepper on the right side
press its play button
wait a couple of seconds and then add another timer
You'll see that the amount of remaining seconds for a running timer is not updated live, but only when refreshing the view by adding another timer to the list.
How can I fix this bug?