SwiftUI调用onDelete删除列表项出现Index out of range崩溃问题
问题根因
- 你使用了
ForEach(multiOptions.indices, id: \.self)的遍历写法,这种方式下ForEach会将传入的索引值作为唯一标识缓存,不会跟随数组的长度变化自动刷新索引映射。当你删除元素后数组长度变小,但ForEach仍会尝试访问原长度对应的旧索引,就触发了「Index out of range」崩溃。 - 额外注意:这种依赖索引作为id的写法,在数组元素重排、中间位置插入内容时,也会出现UI和数据不匹配的问题,本质是索引和数组元素没有做稳定绑定。
修复方案
有两种常用的修复方式,可根据业务需求选择:
方案1:将数组元素包装为可识别类型(更推荐)
给每个选项封装独立的唯一ID,完全脱离对索引的依赖,稳定性最高:
import SwiftUI struct OptionItem: Identifiable { let id = UUID() var content: String } struct OptionsView: View { @State var multiOptions = [OptionItem(content: "")] var body: some View { VStack { List { ForEach($multiOptions) { $item in TextField("Enter your option...", text: $item.content) } .onDelete(perform: removeRow) } Button { multiOptions.append(OptionItem(content: "")) } label: { Image(systemName: "plus.circle") } } } func removeRow(at offsets: IndexSet) { multiOptions.remove(atOffsets: offsets) } }
方案2:强制ForEach跟随数组长度刷新
如果不想修改原有数组结构,可以给ForEach增加id标识,在数组长度变化时强制重新渲染,适配新的索引范围:
List { ForEach(multiOptions.indices, id: \.self) { index in TextField("Enter your option...", text: $multiOptions[index]) } .onDelete(perform: removeRow) } .id(multiOptions.count) // 新增这行即可
内容的提问来源于stack exchange,提问作者Calvin Wood
相关产品推荐
相关产品推荐

