SwiftUI计算属性修改状态触发「视图更新期间修改状态导致未定义行为」错误
问题产生原因
SwiftUI 对视图的渲染更新有严格的时序控制,你定义的timeShown是视图依赖的计算属性,它的求值过程本身就处于视图渲染更新阶段。在这个阶段你直接修改@Binding修饰的startIndex、endIndex两个状态值,相当于在渲染流程还没结束的时候就主动触发新一轮的状态更新,会打乱 SwiftUI 自身的渲染调度逻辑,所以系统会抛出Modifying state during view update, this will cause undefined behavior的警告,严重时会出现界面跳闪、重复渲染、数据和展示不一致的问题。
修复方案
核心原则是:不要在视图渲染阶段(计算属性、body 执行过程)修改任何状态,把状态修改的逻辑移到渲染周期之外的时机执行。
根据你的业务场景可以选择两种修复方案:
- 如果
startIndex、endIndex的取值只和manager.selectedDateByIndex、当前时间挂钩,不需要依赖timeShown的调用时机:
将状态修改逻辑抽离,放到视图的生命周期回调或者状态变更回调中执行:
// 原属性定义保留,删除timeShown内的状态修改代码 var timeIndex: Int let currentDate = Date() let calendar = Calendar.current @Binding var startIndex: Int @Binding var endIndex: Int @EnvironmentObject var manager: BookingManager var timeShown: String { if timeIndex < 10 { return "0\(timeIndex):00" } else if timeIndex > 23 { return "0\(timeIndex % 6):00" } else { return "\(timeIndex):00" } } // 在视图的body末尾添加回调触发逻辑 // 示例如果是SwiftUI视图: var body: some View { // 你的原有视图内容 .onAppear { updateStartEndIndex() } .onChange(of: manager.selectedDateByIndex) { _ in updateStartEndIndex() } } // 单独抽离的状态更新方法 private func updateStartEndIndex() { let hourComponent = calendar.dateComponents([.hour], from: currentDate) let hour = hourComponent.hour! if manager.selectedDateByIndex != 0 { startIndex = 6 endIndex = 30 } else { startIndex = hour endIndex = 24 } }
- 如果你的业务逻辑里
startIndex、endIndex不需要和外部共享状态,仅在当前视图内使用:
可以直接把两个值改为当前视图的局部计算属性,不需要使用@Binding,完全避免状态修改的问题:
// 去掉@Binding修饰,改为计算属性 var startIndex: Int { let hour = calendar.dateComponents([.hour], from: currentDate).hour! return manager.selectedDateByIndex != 0 ? 6 : hour } var endIndex: Int { manager.selectedDateByIndex != 0 ? 30 : 24 } // timeShown保持纯计算逻辑即可 var timeShown: String { if timeIndex < 10 { return "0\(timeIndex):00" } else if timeIndex > 23 { return "0\(timeIndex % 6):00" } else { return "\(timeIndex):00" } }
内容的提问来源于stack exchange,提问作者whiteWolfie
相关产品推荐
相关产品推荐

