编辑2:我在下面添加了一个屏幕录制,这样问题就更清楚了.我对当前的答案并不满意,因为我不明白为什么绑定(binding)在处理数组时会有不同的更新,而在处理单个 struct (即使它们是相同类型的)时会更可靠.
-
编辑:我更新了代码(删除了ForEach并添加了几个print()),使缺少线程安全数组的问题更加明显.
-
我在iOS上编写了一个基本的倒计时计时器,在更新@ State变量之前使用try await Task.sleep(for: .seconds(1))
.当变量MyStruct
时,它似乎更新得很好,但如果我在数组中放置几个MyStruct
—s,那么我会得到奇怪的更新时间, destruct 了基本计时器的功能.
这是我的孤立示例--您可能必须使用refresh the app a few times或用一个按钮替换我的onOuar,才能看到这个行为有多不一致.
import SwiftUI
struct ContentView: View {
@State var first = MyStruct(setTime: 15)
@State var second = MyStruct(setTime: 10)
@State var third = MyStruct(setTime: 5)
@State var array = [MyStruct(setTime: 15), MyStruct(setTime: 10), MyStruct(setTime: 5)]
@State var hasNotAppearedYet = true
var body: some View {
VStack {
Text("Seconds: \(Int(array[0].currentTime))").padding().font(.title3)
Text("Seconds: \(Int(array[1].currentTime))").padding().font(.title3)
Text("Seconds: \(Int(array[2].currentTime))").padding().font(.title3)
Divider()
Text("Seconds: \(first.currentTime)").padding().font(.title3)
Text("Seconds: \(second.currentTime)").padding().font(.title3)
Text("Seconds: \(third.currentTime)").padding().font(.title3)
}
.padding()
.onAppear(){
if(hasNotAppearedYet){
$array[0].startTimer(name: "arrayElement0")
$array[1].startTimer(name: "arrayElement1")
$array[2].startTimer(name: "arrayElement2")
$first.startTimer(name: "FIRST")
$second.startTimer(name: "SECOND")
$third.startTimer(name: "THIRD")
hasNotAppearedYet = false
}
}
}
}
struct MyStruct {
var setTime: Double
var currentTime: Double = 0
}
extension Binding<MyStruct> {
func startTimer(name: String){
Task {
wrappedValue.currentTime = wrappedValue.setTime
print(name, wrappedValue.currentTime)
while (wrappedValue.currentTime > 0) {
try await Task.sleep(for: .seconds(1))
try Task.checkCancellation()
wrappedValue.currentTime -= 1
print(name, wrappedValue.currentTime)
}
}
}
}
#Preview {
ContentView()
}
在模拟器和真实iPhone上同样奇怪的结果