I would like to pass a timer from ContentView
to SecondView
, but I don't know how to manage it because I never used it before.
Can someone figure this out for me?
ContentView
struct ContentView: View {
@State private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var timeRemaining = 10
var body: some View {
NavigationView {
VStack {
Text("\(timeRemaining)")
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
NavigationLink {
SecondView(timer: ???) // <-- What should i pass here?
} label: {
Text("Change View")
}
}
}
}
}
SecondView
struct SecondView: View {
@Binding var timer: ??? // <-- What type?
@State private var timeRemaining = 5
var body: some View {
Text("Hello")
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView(timer: ???) // <-- Same thing here in SecondView preview
}
}
CodePudding user response:
With this timer declaration you are in the Combine
world. Combine
is the reactive framework from Apple.
First you would need to import it:
import Combine
If commented the code but Combine
is a far field and it probably would be best to read the documentation about it, read some tutorials and try some things out.
struct ContentView: View {
// The typ here is Publishers.Autoconnect<Timer.TimerPublisher>
// But we can erase it and the result will be a Publisher that emits a date and never throws an error: AnyPublisher<Date,Never>
@State private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common)
.autoconnect()
.eraseToAnyPublisher()
@State private var timeRemaining = 10
var body: some View {
NavigationView {
VStack {
Text("\(timeRemaining)")
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
NavigationLink {
// pass the publisher on
SecondView(timer: timer)
} label: {
Text("Change View")
}
}
}
}
}
struct SecondView: View {
//You don´t need binding here as this view never manipulates this publisher
var timer: AnyPublisher<Date,Never>
@State private var timeRemaining = 5
var body: some View {
Text("Hello")
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
print(timeRemaining)
}
}
}
}
struct SecondView_Previews: PreviewProvider {
// Creating a static private var should work here !not tested!
@State static private var timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common)
.autoconnect()
.eraseToAnyPublisher()
static var previews: some View {
SecondView(timer: timer)
}
}
CodePudding user response:
You could simply inject the timer publisher, as suggested above, but there may be an even simpler solution:
FirstView
is already updating with every tick of the timer. You could simply pass a timeRemaning
binding to your second view and then it too would just update with every tick of the timer (because timeRemaining
changes on each tick). You can then observe and react to changes of timeRemaining
using .onChange(of:):
struct SecondView: View {
@Binding var timeRemaining: TimeInterval
var body: some View {
Text("Hello")
.onChange(of: timeRemaining) {
if $0 < 0 {
timeRemaining = -1
}
}
}
}