SwiftUI DispatchQueue asyncAfter 在十个计划任务后停止正常工作
SwiftUI DispatchQueue asyncAfter stops working correctly after ten scheduled tasks
如果我 运行 下面的代码,它会正确计数到 10,然后跳过每个奇数。
如果让它 运行 超过 20,它将开始越来越多地跳过(输出将像 1-2-3-4-5-6-7-8-9-10- 12-14-16-18-20-23-26-29 ...).
找不到例如计划任务的限制,所以问你:)
从昨天开始学习SwiftUI,如果这是一个明显的问题,请原谅。
如果它被安排在与 main 不同的 DispatchQueue 中,则没有区别。
感谢您的帮助!
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()
})
}
}
}
这是一种奇怪的行为,甚至事件之间的时间间隔要长得多(例如 2 秒)。
考虑改用 Timer
:
您可以使用多个单独的触发计时器,它们的工作方式与您的单独调度一样:
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
}
}
}
或每 0.2
秒触发一次的单个计时器:
func buttonTap() {
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in
self.counter += 1
if counter == 50 {
timer.invalidate()
}
}
}
此行为称为计时器合并,在这种情况下,发生在彼此 10% 以内的独立计划事件将合并在一起,并且将同时 运行。这是一项省电功能。
有多种解决方案可以避免合并:
- 使用重复计时器;
- 在前一次迭代的完成处理程序中安排每次迭代;或
- 创建不会合并的“严格”GCD 计时器。
重复计时器是最常见的解决方案。
如果我 运行 下面的代码,它会正确计数到 10,然后跳过每个奇数。
如果让它 运行 超过 20,它将开始越来越多地跳过(输出将像 1-2-3-4-5-6-7-8-9-10- 12-14-16-18-20-23-26-29 ...).
找不到例如计划任务的限制,所以问你:) 从昨天开始学习SwiftUI,如果这是一个明显的问题,请原谅。
如果它被安排在与 main 不同的 DispatchQueue 中,则没有区别。
感谢您的帮助!
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()
})
}
}
}
这是一种奇怪的行为,甚至事件之间的时间间隔要长得多(例如 2 秒)。
考虑改用 Timer
:
您可以使用多个单独的触发计时器,它们的工作方式与您的单独调度一样:
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
}
}
}
或每 0.2
秒触发一次的单个计时器:
func buttonTap() {
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in
self.counter += 1
if counter == 50 {
timer.invalidate()
}
}
}
此行为称为计时器合并,在这种情况下,发生在彼此 10% 以内的独立计划事件将合并在一起,并且将同时 运行。这是一项省电功能。
有多种解决方案可以避免合并:
- 使用重复计时器;
- 在前一次迭代的完成处理程序中安排每次迭代;或
- 创建不会合并的“严格”GCD 计时器。
重复计时器是最常见的解决方案。