Reputation: 229
If I run the code below, it counts correctly to 10 and then skips every odd number.
If you let it run beyond 20, it will start skipping more and more (the output will be like 1-2-3-4-5-6-7-8-9-10-12-14-16-18-20-23-26-29 ...).
Couldn't find documentation of e.g. a limit of scheduled tasks, so asking you :) Learning SwiftUI since yesterday, so pardon if it's an obvious question.
If it's scheduled in a different DispatchQueue than main, it makes no difference.
Thanks for helping!
import SwiftUI
struct ContentView: View {
@State private var counter : Int = 0
func buttonTap() {
let time : DispatchTime = .now()
var delay : Double = 0
for _ in 1...50 {
delay = delay + 0.2
DispatchQueue.main.asyncAfter(deadline: time + delay) {
counter += 1
}
}
}
var body: some View {
ZStack {
Color(.black)
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
Text(String(counter))
.foregroundColor(.green)
.padding()
Text("Button")
.foregroundColor(.green)
.offset(y: 50)
.onTapGesture(perform: {
buttonTap()
})
}
}
}
Upvotes: 0
Views: 974
Reputation: 437632
This behavior is known as timer coalescing, where independently scheduled events that occur within 10% of each other will be coalesced together, and will be run at the same time. This is a power saving feature.
There are a variety of solutions to avoid coalescing:
The repeating timer is the most common solution.
Upvotes: 1
Reputation: 154603
That is an odd behavior, and it even occurs for much longer time intervals between events (for example, 2 seconds).
Consider using a Timer
instead:
You can use multiple single fire timers that work just like your separate dispatches:
func buttonTap() {
var delay : Double = 0
for _ in 1...50 {
delay = delay + 0.2
Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { timer in
self.counter += 1
}
}
}
or a single timer that fires every 0.2
seconds:
func buttonTap() {
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in
self.counter += 1
if counter == 50 {
timer.invalidate()
}
}
}
Upvotes: 1