我在删除项目时遇到 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())
}
}
}
现在是奇怪的行为。点击一行的按钮:
我无法弄清楚我做错了什么。
更新
显然该问题与 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?