Search code examples
swifttimerswiftuicombinepublisher

How do I resume a published timer in SwiftUI after navigating to a different page?


In the following Playground example, the UI updates with the current date correctly, however when navigating away from the page and coming back the timer does not resume ticking:

  import SwiftUI
  import PlaygroundSupport

  struct MainTabView: View {
    let timer = Timer.publish(every: 1, on: .main, in: .common)

    @State var time = Date()

    var body: some View {
        TabView {
            VStack {
                Text("\(time)").onReceive(self.timer) { self.time = $0 }
            }
            .onAppear { _ = self.timer.connect() }
            .tabItem {
                Text("Page 1")
            }

            Text("Page 2").tabItem {
                Text("Page 2")
            }

            Text("Page 3").tabItem {
                Text("Page 3")
            }
        }
    }
}

PlaygroundPage.current.setLiveView(MainTabView())

How do I have the timer start updating again when the page starts showing?

I have seen solutions that involve wrapping the Timer in another class, but nothing that can be done in the View.

I thought calling in connect() in onAppear {} would do it.


Solution

  • Reinitializing your timer and date inside the onAppear would work:

    struct ContentView: View {
        @State private var timer = Timer.publish(every: 1, on: .main, in: .common)
        @State var time = Date()
    
        var body: some View {
            TabView {
                VStack {
                    Text("\(time)").onReceive(self.timer) { self.time = $0 }
                }
                .onAppear(perform: {
                    self.time = Date()
                    self.timer = Timer.publish(every: 1, on: .main, in: .common)
                    _ = self.timer.connect()
                })
                .tabItem {
                    Text("Page 1")
                }
    
                Text("Page 2").tabItem {
                    Text("Page 2")
                }
    
                Text("Page 3").tabItem {
                    Text("Page 3")
                }
            }
        }
    }