SwiftUI定时器中@State数组元素丢失问题排查
问题原因分析
你遇到的问题核心是代码执行顺序和异步操作的特性:
- 按钮的action闭包是同步执行的:先给
theMoveArray添加两个元素,此时print1输出2完全符合预期;紧接着创建的1秒触发定时器,其闭包不会立刻执行,而是进入异步队列等待调度; - 定时器创建完成后,你立刻同步执行了
theMoveArray.removeAll(),直接把数组清空; - 1秒后定时器闭包触发时,访问的
theMoveArray已经是被清空后的状态,所以print2输出0,进而触发数组越界问题。
注:这里的问题和@State的视图刷新逻辑无关,纯粹是同步代码与异步定时器的执行顺序导致的。
修复方案
如果需要定时器遍历完数组元素后再清空数组,把removeAll()移到定时器的终止逻辑里即可:
Button { theMoveArray.append(theMove) theMoveArray.append(theMove2) theCounter = 0 let theArrayBounds = theMoveArray.count - 1 print("\(theMoveArray.count)") //print1 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in guard let self = self else { timer.invalidate() return } print("\(self.theMoveArray.count)")//print2 if self.theCounter <= theArrayBounds { print("Timer fired! 元素内容:\(self.theMoveArray[self.theCounter])") } else { timer.invalidate() self.theMoveArray.removeAll() // 遍历完成后再清空数组 } self.theCounter += 1 } } label: { Text("The Button") .frame(width: 100, height: 100) }
额外优化建议:
theArrayBounds用let声明即可,无需var;- 定时器闭包添加
[weak self]捕获,避免潜在的循环引用风险。
内容的提问来源于stack exchange,提问作者user18176479
相关产品推荐
相关产品推荐

