在 ObservableObject 中重新加载 @Published 数组时,SwiftUI ForEach List 保留修改后的值

SwifUI ForEach List keeps modified values when reloading a @Published array inside ObservableObject

我有一个 SwiftUI 列表,它使用绑定到 ObservableObject

内的 @Published 数组的 ForEach 循环填充

列表中的元素可以用 on/off 标志修改。当列表被清除时,所有项目似乎都从 UI 中删除,但是当数据被重新获取并加载到 @Published 数组中时,UI 仍然显示先前修改的元素的状态。正如您在以下视频中看到的那样:

重现它的代码:

struct ListView: View {
    
    @ObservedObject private var viewModel = ListViewModel()

    var body: some View {
            VStack {
                List {
                    ForEach(viewModel.list, id: \.self) { element in
                        ElementRow(element: element)
                    }
                }
                HStack {
                    Button(action: { viewModel.fetch() }) { Text("Refresh") }
                    Button(action: { viewModel.remove() }) { Text("Remove") }
                }
            }.onAppear {
                viewModel.fetch()
            }
        }
    }

struct ElementRow: View {
    @ObservedObject var element: ElementViewModel
    
    var body: some View {
        HStack {
            Text(element.id)
            Spacer()
            Toggle("", isOn: $element.on )
        }
    }
}

class ListViewModel : ObservableObject {
    
    @Published var list: [ElementViewModel] = []
    
    func fetch() {
        list.append(contentsOf: [ElementViewModel(id: "0", on: false), ElementViewModel(id: "1", on: false)])
    }
    func remove() {
        list.removeAll()
    }
}

class ElementViewModel : ObservableObject, Hashable {
    
    var id: String = ""
    @Published var on: Bool = false
    
    init(id: String, on: Bool) {
        self.id = id
        self.on = on
    }
    static func == (lhs: ElementViewModel, rhs: ElementViewModel) -> Bool {
        lhs.id == rhs.id
    }
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

需要更改什么才能使列表中的所有元素在刷新时保持关闭状态?

您的模型对象被解释为相等,因此视图不会更新(List 缓存行类似于 UITableView)。

在下面找到修复程序。使用 Xcode 12.4 / iOS 14.4

测试
class ElementViewModel : ObservableObject, Hashable {

    // ... other code

    static func == (lhs: ElementViewModel, rhs: ElementViewModel) -> Bool {
        lhs.id == rhs.id && lhs.on == rhs.on    // << here !!
    }

    // ... other code
}