SwiftUI:删除最后一个元素时索引超出范围

SwiftUI: Index out of range when last element gets removed

我有一个用 LazyVStack 制作的清单,我为清单项目实现了删除功能,但出于某种原因,只有当我尝试删除最后一个时,app 才会崩溃并显示“索引超出范围”元素

这是我的代码:

struct ChecklistView: View {
    // Properties
    // ==========
    @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: $checklistItems[item], viewModel: viewModel)
                            .listRowInsets(.init(top: 0, leading: 8, bottom: 0, trailing: 0))
                            .padding(.horizontal, 12)
                            .padding(.top, 12)
                            .padding(.bottom, 4)

                        Button {
                            //Prints the correct index number for the last element in the array, but when I remove the last element, always crashes.
                            print(index)
                            if let index = checklistItems.firstIndex(where: {[=10=].id == checklistItems[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)
        )
    }
}

您的 ForEach(checklistItems) { item in 中的 item 不是数组的索引 checklistItems 个,是 ChecklistItem 个。但是,您将其用作索引 RowView(checklistItem: $checklistItems[item], ...。这是不正确的。

使用 indices 尝试此方法来解决您的问题:

ForEach(checklistItems.indices, id: \.self) { ndx in
    HStack {
        RowView(checklistItem: $checklistItems[ndx], viewModel: viewModel)
            .listRowInsets(.init(top: 0, leading: 8, bottom: 0, trailing: 0))
            .padding(.horizontal, 12)
            .padding(.top, 12)
            .padding(.bottom, 4)

        Button {
            print(ndx)
            checklistItems.remove(at: ndx)
        } label: {
            Text("X")
        }
    }
    Divider().frame(width: 311)
}

你也可以使用这个:

ForEach(Array(zip(checklistItems.indices, checklistItems)), id: \.0) { ndx, item in

我找到了解决方案,我将 forEach 更改为:

ForEach(checklistItems.indices, id: \.self) { index in
                    HStack {
                        RowView(
                            checklistItem:
                                Binding(
                                    get: { self.checklistItems[index] },
                                    set: { self.checklistItems[index] = [=10=] }
                                ),
                            viewModel: viewModel
                        )
                        .padding(.leading, 12)

                        if checklistEditMode {
                            Button {
                                checklistItems.remove(at: index)
                            } label: {
                                Image("XCircle")
                                    .resizable()
                                    .frame(width: 18, height: 18)
                            }
                            .padding(.trailing, 12)
                        }
                    }
                    .padding(.horizontal, 12)
                    .padding(.top, 12)
                    .padding(.bottom, 4)

                    Divider()
                        .frame(width: 311)
                }

它现在可以正常工作,没有崩溃,感谢