swiftswiftuicombine

Timer publisher init timer after button click


In all tutorials and in official documentation I only see initialization of timer straight up when the view loads.

@State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

and later on

.onReceive(timer) {....}

but how should I init timer only on button click and assign it to the unassigned / not connected timer.

Later on I will need to cancel and reconnect, but that is not the issue here. Issue here is connecting only after button click.

I tried to init it like this

@State private var timer: Cancellable?

....

timer = Timer.publish(every: 1, on: .main, in: .common).connect()

But I can not call onReceive on timer inited like this, because first:

Protocol 'Cancellable' as a type cannot conform to 'Publisher'

and second

Argument type 'Cancellable?' does not conform to expected type 'Cancellable'

Solution

  • Update: Now there is a built-in TimelineView for this.

    Just put the timer in a child view and control its visibility with a bool. When the TimerView is removed the state is destroyed and the timer stops.

    struct ContentView: View {
        @State var started = false
    
        var body: some View {
            VStack {
                Button(started ? "Stop" : "Start") {
                    started.toggle()
                }
                if started {
                    TimerView()
                }
            }
        }
    }
    
    struct TimerView: View {
    
        @State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
        ...