To run some code routinely, maybe to make a commencement clock or comparable, you ought to utilize Clock and the onReceive() modifier.
The capacity to run some code occasionally is a significant errand in iOS development.
For instance, this code makes a timer distributer that fires consistently, refreshing a label with the ongoing time:
How to use Timer in SwiftUI
- You make a Timer and
- Listen to it with the .onReceive modifier.
struct ContentView: View {
@State var startDate = Date.now
@State var timeElapsed: Int = 0
// 1
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Text("Time elapsed: \(timeElapsed) sec")
// 2
.onReceive(timer) { firedDate in
print("timer fired")
// 3
timeElapsed = Int(firedDate.timeIntervalSince(startDate))
}
.font(.largeTitle)
}
}
1) We make timer utilizing Timer.publish(every: 1, on: .primary, in: .common).autoconnect().
For this situation, we believe that our clock should set off each second.
We run it on the .main run circle since we use it to refresh the UI.
Last boundary is run circle mode, you can think it as a sort of need. For UI-related stuff, you use .common run loop.
The .autoconnect() part is advising the timer to begin once we pay attention to it.
2. We pay attention to a timer utilizing the .onReceive modifier.
3 Consistently, an onReceive conclusion will set off with a terminated date boundary. We utilize this to work out the time slipped by for this situation.
It means quite a bit to utilize .primary for the runloop choice, on the grounds that our timer will refresh the UI. With respect to the .familiar mode, that permits the clock to run close by other normal occasions – for instance, assuming that the text was in a parchment view that was moving.
As may be obvious, the onReceive() conclusion gets passed in some info containing the ongoing date. In the code above we relegate that directly to currentDate, yet you could utilize it to compute how long has passed since a past date.
To make a commencement timer or stopwatch, you ought to make a state to follow how long remaining parts, then, at that point, deduct from that when the timer fires.
How to cancel Timer in SwiftUI
To cancel or stop a timer use timer.upstream.connect().cancel().
We can add a Stop button to the timer:
struct ContentView: View {
@State var startDate = Date.now
@State var timeElapsed: Int = 0
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
Text("Time elapsed: \(timeElapsed) sec")
.onReceive(timer) { firedDate in
print("timer fired")
timeElapsed = Int(firedDate.timeIntervalSince(startDate))
}
Button("Stop") {
timer.upstream.connect().cancel()
}
}
.font(.largeTitle)
}
}
Restart a timer in SwiftUI
The best way to restart a timer is to reproduce and reconnect it.
In this example, we reproduce a timer in the Resume button’s activity.
struct ContentView: View {
@State var startDate = Date.now
@State var timeElapsed: Int = 0
// 1
@State var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
Text("Time elapsed: \(timeElapsed) sec")
.onReceive(timer) { firedDate in
print("timer fired")
timeElapsed = Int(firedDate.timeIntervalSince(startDate))
}
Button("Pause") {
timer.upstream.connect().cancel()
}
Button("Resume") {
// 2
timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
}
}
.font(.largeTitle)
}
}
- We need to have the option to reproduce a timer, so we change from let to @State var
- We add a button to reproduce a timer
Leave a Reply