Skip to content

Instantly share code, notes, and snippets.

@mattyoung
Last active June 19, 2020 20:54
Show Gist options
  • Save mattyoung/cdf674a64615cc05248539f5c9b79243 to your computer and use it in GitHub Desktop.
Save mattyoung/cdf674a64615cc05248539f5c9b79243 to your computer and use it in GitHub Desktop.
// Problem with Timer.publisher not work in navigation stack
//
// Timer.publisher *do not* fire reliably if the View is shown through NavigationLink()
// Work fine if it's not inside navigation stack
//
// The Pointfree Publisher.Timer do not fire at all when navigate in
// but start receiving timer when pop back out navigation stack
// run debug preview and watch print message in .onReceive()
import SwiftUI
import Combine
import CombineSchedulers
struct RootView: View {
@State var currentDate = Date()
let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
VStack {
Text("\(currentDate)")
Group {
Text("Timer.publisher do not work reliably if navigated to the view")
Text("Tap the button below to view the same DetaisView")
NavigationLink(destination: DetailsTimerPublisherView()) {
Text("Navigate to DetailsView")
}
}
Group {
Text("But .scheduleTimer works!")
NavigationLink(destination: DetailsScheduleTimerView()) {
Text("Navigate to DetailsScheduleTimerView")
}
}
Group {
Text("Pointfree Publishers.Timer do not work")
Text("When navigate into")
Text("But it start firing when pop back Nav stack")
Text("Run Debug to see print out from .onReceive")
NavigationLink(destination: DetailsPointfreePublisherTimerView()) {
Text("Navigate to DetailsPointfreePublisherTimerView")
}
}
}
.onReceive(timer) { now in
self.currentDate = now
}
.navigationBarTitle("Root")
}
}
}
// Timer.Publisher do not work reliably
struct DetailsTimerPublisherView: View {
@State var currentDate = Date()
// if we do this, doesn't work at all
// let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
// so declare let, instantiate in init
// timer fire once in a while, not on "every"
private let timer: Combine.Publishers.Autoconnect<Timer.TimerPublisher>
init() {
self.timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
}
var body: some View {
Text("\(currentDate)")
.onReceive(timer) { now in
self.currentDate = now
}
.navigationBarTitle("Details")
}
}
struct DetailsPointfreePublisherTimerView: View {
@State var currentDate = Date()
let timer = Publishers.Timer(every: .seconds(1), scheduler: DispatchQueue.main).autoconnect()
var body: some View {
Text("\(currentDate)")
.onReceive(timer) { timer in // SchedulerTimeType
print(type(of: timer)) // run "Debug Preview" to see print out when view pop back up nav stack
self.currentDate = Date()
}
.navigationBarTitle("Details")
}
}
// Timer.scheduledTimer() arrange this way works
struct DetailsScheduleTimerView: View {
@State var currentDate = Date()
@State private var timer: Timer?
var body: some View {
Text("\(currentDate)")
.onAppear {
print("Appear")
self.timer = Timer.scheduledTimer(
withTimeInterval: 0.5, repeats: true
) { timer in
self.currentDate = timer.fireDate
}
}
.onDisappear {
print(" Disappear")
if let timer = self.timer {
timer.invalidate()
self.timer = nil
}
}
.navigationBarTitle("Details")
}
}
struct KeepTimerAliveThroughNavigation: View {
var body: some View {
VStack {
RootView()
Text("Timers all works here at the root of NavView")
Text("DetailsView Displayed Outside of NavigationView")
DetailsTimerPublisherView()
DetailsScheduleTimerView()
// works here, uncomment and see
// comment out to not get confuse with print message inside
// DetailsPointfreePublisherTimerView()
}
}
}
struct KeepTimerAliveThroughNavigation_Previews: PreviewProvider {
static var previews: some View {
KeepTimerAliveThroughNavigation()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment