从 SwiftUI 中的列表中删除绑定

Posted

技术标签:

【中文标题】从 SwiftUI 中的列表中删除绑定【英文标题】:Delete a Binding from a list in SwiftUI 【发布时间】:2021-10-28 02:13:49 【问题描述】:

我试图从 Swift 和 SwiftUI 的列表中简单地删除一个元素。如果没有在ForEach 循环中绑定某些东西,它确实会被删除。但是,在绑定某些东西时,它会因错误Index out of range 而崩溃。 ForEach 循环似乎是恒定的,不更新,并试图在特定索引处呈现。

示例查看代码:

@ObservedObject var todoViewModel: TodoViewModel
//...
ForEach(self.todoViewModel.todos.indices)  index in
    TextField("Test", text: self.$todoViewModel.todos[index].title)
        .contextMenu(ContextMenu(menuItems: 
            VStack 
                Button(action: 
                    self.todoViewModel.deleteAt(index)
                , label: 
                    Label("Delete", systemImage: "trash")
                )
            
        ))                                    

示例视图模型代码:

final class TodoViewModel: ObservableObject 
    @Published var todos: [Todo] = []
    
    func deleteAt(_ index: Int) -> Void 
        self.todos.remove(at: index)
    

示例型号代码:

struct Todo: Identifiable 
    var id: Int
    var title: String = ""

有谁知道如何从ForEach 循环中绑定的列表中正确删除一个元素?

【问题讨论】:

这是否回答了您的问题***.com/a/58911168/12299030? 遗憾的是没有。我也注意到了这一点,但是您可以在代码中看到我没有使用 ForEach 中的任何范围 【参考方案1】:

发生这种情况是因为您通过indices 进行枚举并通过ForEach 内部的索引引用绑定

我建议你切换到ForEachIndexed:这个包装器会将索引和正确的绑定传递给你的块:

struct ForEachIndexed<Data: MutableCollection&RandomAccessCollection, RowContent: View, ID: Hashable>: View, DynamicViewContent where Data.Index : Hashable

    var data: [(Data.Index, Data.Element)] 
        forEach.data
    
    
    let forEach: ForEach<[(Data.Index, Data.Element)], ID, RowContent>
    
    init(_ data: Binding<Data>,
         @ViewBuilder rowContent: @escaping (Data.Index, Binding<Data.Element>) -> RowContent
    ) where Data.Element: Identifiable, Data.Element.ID == ID 
        forEach = ForEach(
            Array(zip(data.wrappedValue.indices, data.wrappedValue)),
            id: \.1.id
        )  i, _ in
            rowContent(i, Binding(get:  data.wrappedValue[i] , set:  data.wrappedValue[i] = $0 ))
        
    
    
    init(_ data: Binding<Data>,
         id: KeyPath<Data.Element, ID>,
         @ViewBuilder rowContent: @escaping (Data.Index, Binding<Data.Element>) -> RowContent
    ) 
        forEach = ForEach(
            Array(zip(data.wrappedValue.indices, data.wrappedValue)),
            id: (\.1 as KeyPath<(Data.Index, Data.Element), Data.Element>).appending(path: id)
        )  i, _ in
            rowContent(i, Binding(get:  data.wrappedValue[i] , set:  data.wrappedValue[i] = $0 ))
        
    
    
    var body: some View 
        forEach
    

用法:

ForEachIndexed($todoViewModel.todos)  index, todoBinding in
    TextField("Test", text: todoBinding.title)
        .contextMenu(ContextMenu(menuItems: 
            VStack 
                Button(action: 
                    self.todoViewModel.deleteAt(index)
                , label: 
                    Label("Delete", systemImage: "trash")
                )
            
        ))

【讨论】:

效果非常好!感谢您的出色工作!

以上是关于从 SwiftUI 中的列表中删除绑定的主要内容,如果未能解决你的问题,请参考以下文章

从 SwiftUI 的列表中删除列表元素

从 SwiftUI 的列表中删除列表元素

SwiftUI - 删除绑定数组中的元素会导致错误

删除具有绑定布尔值的列表项 - SwiftUI

如何从 Mac OS 中的 SwiftUI 列表中删除底部/顶部项目填充

如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象