首页 > 解决方案 > 删除项目时列表的奇怪行为

问题描述

删除项目时,我遇到了 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?

标签: swiftui

解决方案


推荐阅读