@Published 属性不更新嵌套视图模型中的视图 - SwiftUI

Spd*_*laz 4 swiftui

我不确定当我的视图模型嵌套在另一个视图模型中时为什么我的视图没有更新。我的理解是,子视图模型中的 @Published 属性会触发父视图模型中的更改,从而导致将更改推送到 UI。

这是子视图模型:

class FilterViewModel : ObservableObject, Identifiable {

    var id = UUID().uuidString
    var name  = ""
    var backgroundColour = ""
    @Published var selected = false

    private var cancellables = Set<AnyCancellable>()

    init(name: String){
        self.name = name
    
        $selected.map { _ in
            self.selected ? "Orange" : "LightGray"
        }
        .assign(to: \.backgroundColour, on: self)
        .store(in: &cancellables)
     }

    func changeSelected() {
    
        self.selected = !self.selected
    }
}
Run Code Online (Sandbox Code Playgroud)

以下内容按预期工作,单击按钮后背景颜色发生变化。

struct ContentView: View {

    @ObservedObject var filterVM = FilterViewModel(name: "A")


    Button(action: { filterVM.changeSelected()}, label: {
        Text(filterVM.name)
            .background(Color(filterVM.backgroundColour))
    })
}
Run Code Online (Sandbox Code Playgroud)

但是,我想要尝试一系列过滤器视图模型:

class FilterListViewModel: ObservableObject {

    @Published var filtersVMS = [FilterViewModel]()

    init(){
        filtersVMS = [
            FilterViewModel(name: "A"),
            FilterViewModel(name: "B"),
            FilterViewModel(name: "C"),
            FilterViewModel(name: "D")
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,单击按钮时,以下视图不会更新

struct ContentView: View {

    @ObservedObject var filterListVM = FilterListViewModel()

    Button(action: { filterListVM[0].changeSelected()}, label: {
        Text(filterListVM[0].name)
            .background(Color(filterListVM[0].backgroundColour))
    })
}
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 5

替代解决方案是为子模型使用分离视图:

struct FilterView: View {
    @ObservedObject var filterVM: FilterViewModel

    var body: some View {
      Button(action: { filterVM.changeSelected()}, label: {
        Text(filterVM.name)
            .background(Color(filterVM.backgroundColour))
      })
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在在父视图中我们可以将它用作

struct ContentView: View {

    @ObservedObject var filterListVM = FilterListViewModel()

    // ...

    FilterView(filterVM: filterListVM[0])
}
Run Code Online (Sandbox Code Playgroud)