从列表中删除项目时索引不更新

Posted

技术标签:

【中文标题】从列表中删除项目时索引不更新【英文标题】:Indices don't update when deleting item from list 【发布时间】:2021-04-22 03:58:39 【问题描述】:

我想创建一个视图,我可以将数组传递到该视图中并让视图编辑数组。下面的代码是一个简化的例子:

struct Item: Identifiable 
  var name: String
  var id = UUID()


struct EditItems: View 
  @Binding var item_list: [Item]
  
  var body: some View 
    List 
      ForEach(item_list.indices)  idx in
        Text(item_list[idx].name)
      
      .onDelete(perform: deleteItem)
    
    .toolbar 
      ToolbarItem(placement: .principal) 
        EditButton()
      
    
  
  
  func deleteItem(at offsets: IndexSet) 
    item_list.remove(atOffsets: offsets)
  

这首先编译并运行。我可以点击“编辑”并删除列表项。删除列表项后,当我点击“完成”时,我得到“致命错误:索引超出范围”。调试器告诉我,我的列表有 7 个项目,但 Text(item_list[idx].name) 行正在尝试使用 idx = 7 执行。

因此,在删除项目后,ForEach 似乎仍在旧索引上运行,而不是新的较短索引。这是因为item_list 不是@State?当我尝试同时使用@State@Binding 时,我遇到了一堆错误。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

ForEach 的初始化器接受一个范围,只能用于常量数据。

来自Apple's docs:

实例只读取提供的数据的初始值并且 不需要跨更新识别视图。

使用其他 ForEach 初始化器之一,例如:

ForEach(item_list.enumerated(), id: \.self)  idx, element in

【讨论】:

好吧,我会的,我从来没有注意到其中一些是恒定的,而另一些则不是。谢谢!【参考方案2】:

您使用了 ForEach 的构造函数,它创建 constant 容器,使用不同的容器,带有显式标识符,例如

List 
  ForEach(item_list.indices, id: \.self)  idx in    // << here !!
    Text(item_list[idx].name)
  

【讨论】:

以上是关于从列表中删除项目时索引不更新的主要内容,如果未能解决你的问题,请参考以下文章

删除项目后如何更新列表视图?

从 SwiftUI 中的列表中删除绑定

删除一项后组件列表不更新状态

我想从列表视图中删除一个项目

SwiftUI:从 ForEach 中删除项目导致索引超出范围

使用微调器从自定义列表视图中删除了错误的行