删除项目时列表的奇怪行为

时间:2021-04-03 07:23:35

标签: swiftui

我在删除项目时遇到 List 的奇怪行为。

数据模型

class Item: Identifiable, ObservableObject {
    let id = UUID()
    @Published var name: String
    
    internal init(name: String) {
        self.name = name
    }
}

查看模型

class ListViewModel: ObservableObject {
    @Published var items: [Item]
    
    internal init(items: [Item]) {
        self.items = items
    }

    internal init() {
        self.items = [Item(name: "A"), Item(name: "B"), Item(name: "C"), Item(name: "D")]
    }
}

查看

struct ContentView: View {
    @ObservedObject var viewModel = ListViewModel()

    var body: some View {
        List {
            ForEach(0 ..< viewModel.items.count, id: \.self) { idx in

                HStack {
                    Text("\(viewModel.items[idx].name)")
                    Spacer()
                    Button("Edit") {
                        // To be done
                    }
                    .buttonStyle(BorderlessButtonStyle())
                    Button("Delete") {
                        viewModel.items.remove(at: idx)
                    }
                    .buttonStyle(BorderlessButtonStyle())
                }
            }
        }
    }
}

这很好用。点击“删除”按钮,相关项目将按预期删除。

然后我稍微整理了一下代码,为每一行添加了一个视图。

struct ContentView: View {
    @ObservedObject var viewModel = ListViewModel()

    var body: some View {
        List {
            ForEach(0 ..< viewModel.items.count, id: \.self) { idx in

//                HStack {
//                    Text("\(viewModel.items[idx].name)")
//                    Spacer()
//                    Button("Edit") {
//                        // To be done
//                    }
//                    .buttonStyle(BorderlessButtonStyle())
//                    Button("Delete") {
//                        viewModel.items.remove(at: idx)
//                    }
//                    .buttonStyle(BorderlessButtonStyle())
//                }

                Row(item: viewModel.items[idx]) { action in
                    switch action {
                    case .delete:
                        viewModel.items.remove(at: idx)
                    case .edit:
                        // To be done
                        break
                    default:
                        break
                    }
                }
            }
        }
    }
}


enum ActionType {
    case new
    case edit
    case delete
    case cancel
}

struct Row: View {
    @State var item: Item
    var action: (_ type: ActionType) -> Void

    var body: some View {
        HStack {
            Text("\(item.name)")
            Spacer()
            Button("Edit") {
                action(.edit)
            }
            .buttonStyle(BorderlessButtonStyle())
            Button("Delete") {
                action(.delete)
            }
            .buttonStyle(BorderlessButtonStyle())
        }
    }
}

现在是奇怪的行为。点击一行的按钮:

  1. 右行从 viewModel 中移除
  2. 无论点击哪个删除按钮,列表显示错误的项目总是删除最后一行

我无法弄清楚我做错了什么。

更新

显然该问题与 ForEach 相关,以下代码正常工作。

struct ContentView: View {
    @ObservedObject var viewModel = ListViewModel()

    var body: some View {

        List(viewModel.items, id: \.id) { item in
            Row(item: item) { action in
                switch action {
                case .delete:
                    if let idx = viewModel.items.firstIndex(where: { $0.id == item.id }) {
                        viewModel.items.remove(at: idx)
                    }
                case .edit:
                    break
                default:
                    break
                }
            }
        }
    }
}

我是否以错误的方式使用 ForEach?

0 个答案:

没有答案