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())
}
}
}
现在奇怪的行为。点击一行的按钮:
- 从 viewModel 中删除右行
- 列表显示错误的项目总是删除最后一行,无论点击哪个删除按钮
我无法弄清楚我做错了什么。
更新
显然这个问题与 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?
解决方案
推荐阅读
- docker - 在同一个容器上并行运行 docker exec
- python - 列出 S3 存储桶并使用查询器输出它们
- linux - gdb 如何启动一个汇编编译程序并一次执行一行?
- html - 设置输入范围
- apache - .htaccess 重写以仅显示根 url 并隐藏 /folder 之后的所有内容
- python - Flask API 为特定的 URl 提供 URL not found 错误
- javascript - 如何在axios中迭代在每个循环中返回新的百分比+数组
- php - 如何在目标网址之前将短链接网站重定向到博主
- xcode - NSErrorFailingURLKey=***
- maven - NoSuchMethodError: com.google.common.base.Splitter.splitToList(Ljava/lang/CharSequence;)Ljava/util/List;