SwiftUI中Form删除行触发Index out of range错误而List正常是什么原因?
问题根本原因
1. iOS 14 系统 Form 底层实现缺陷
iOS 14 中 Form 和 List 虽然都基于 UITableView 实现,但二者对动态数组更新的状态同步逻辑存在差异:
List针对 SwiftUI 绑定数组的删除操作做了专门适配,每次数据源变更后会立刻刷新内部 cell 缓存,和最新的数组状态对齐Form在 iOS 14 没有做对应的适配,删除数组元素后,内部缓存的 cell 索引没有及时更新,仍然会尝试访问已经被删除的索引位置,触发数组越界崩溃。删除最底部行时刚好索引和更新后的数组长度匹配,因此不会触发崩溃。
2. ForEach 标识不稳定放大了问题
你当前使用 ForEach(self.$viewModel.model.components, id: \.self) 以元素自身作为唯一标识,当数组元素发生删除操作时,ForEach 生成的绑定索引本身就会发生偏移,和 Form 残留的旧索引缓存叠加后,直接触发越界报错。
兼容 iOS 14 的解决方案
方案1:使用稳定的唯一标识作为 ForEach 的 ID
将数组元素替换为符合 Identifiable 协议的结构体,避免用元素值/索引作为唯一标识:
// 替换原来的String数组元素 struct Component: Identifiable { let id = UUID() var content: String } struct MyModel { var components: [Component] } // ForEach写法简化,不需要手动指定id ForEach($viewModel.model.components) { $component in Text(component.content) }
方案2:手动触发 Form 全量重绘
给 Form 添加 id 修饰符,绑定数组长度,每次数组元素数量变化时强制 Form 完全重绘,清空旧的缓存索引:
Form { Section(header: Text("Components")) { ForEach(self.$viewModel.model.components, id: \.self) { $component in Text(component) } .onDelete(perform: delete) } } .id(viewModel.model.components.count) // 新增这行
方案3:升级最低适配版本
该问题在 iOS 15 及以上系统已经被苹果官方修复,如果你的项目后续可以把最低适配升级到 iOS 15+,不需要修改代码也可以正常运行。
内容的提问来源于stack exchange,提问作者Bart van Kuik
相关产品推荐
相关产品推荐

