SwiftUI 删除列表最后一个元素时出现Index out of range崩溃
问题根因
- 你错误地将遍历得到的
ChecklistItem实例作为数组下标使用,访问checklistItems[item]属于非法操作。数组下标只能为Int类型,你这种写法本身就存在逻辑漏洞,当删除最后一个元素时数组长度缩减,失效的下标访问直接触发越界崩溃。 - 删除逻辑冗余,你已经持有当前遍历到的
item实例,完全不需要再通过数组下标访问获取id,直接使用item.id即可。
修复方案
1. 修改ForEach遍历方式
直接遍历绑定数组,拿到单个元素的绑定,避免手动处理下标:
// 原来的写法 ForEach(checklistItems) { item in // 修改为 ForEach($checklistItems) { $item in
2. 修正RowView的绑定传参
不需要再通过数组下标取绑定,直接传入遍历得到的$item:
// 原来的写法 RowView(checklistItem: $checklistItems[item], viewModel: viewModel) // 修改为 RowView(checklistItem: $item, viewModel: viewModel)
3. 简化删除逻辑
直接用当前item的id查找索引,避免非法下标访问:
Button { if let index = checklistItems.firstIndex(where: { $0.id == item.id }) { checklistItems.remove(at: index) } } label: { Text("X") }
修复后完整代码
struct ChecklistView: View { // 属性 // ========== @ObservedObject var checklist = Checklist() @ObservedObject var viewModel: ChecklistViewModel @Binding var checklistItems: [ChecklistItem] @State var newItemName = "" @State var newChecklistItemViewIsVisible = false @State var presentAddNewItem = true let offlineMode: Bool var body: some View { VStack { LazyVStack { ForEach($checklistItems) { $item in HStack { RowView(checklistItem: $item, viewModel: viewModel) .listRowInsets(.init(top: 0, leading: 8, bottom: 0, trailing: 0)) .padding(.horizontal, 12) .padding(.top, 12) .padding(.bottom, 4) Button { if let index = checklistItems.firstIndex(where: {$0.id == item.id}){ checklistItems.remove(at: index) } } label: { Text("X") } } Divider() .frame(width: 311) } } } .frame(width: UIScreen.main.bounds.width - 32) .background(backgroundSecondary) .cornerRadius(16) .overlay( RoundedRectangle(cornerRadius: 16) .stroke(borderGray, lineWidth: 1) ) } }
内容的提问来源于stack exchange,提问作者Hussein
相关产品推荐
相关产品推荐

