You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 22:09:01