Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell SwiftUI views to bind to more than one nested ObservableObject

I have two classes nested in another class, which is an observable object in a SwiftUI view. Even though properties in the nested classes are declared as @Published, their values (when they change) do not update in the main view.

A similar question has been asked here, and I could use it to get it to work for one of the two subclasses, but not both.

How to tell SwiftUI views to bind to nested ObservableObjects

This is the model:

class Submodel1: ObservableObject {
  @Published var count = 0
}

class Submodel2: ObservableObject {
  @Published var count = 0
}

class Model: ObservableObject {
  @Published var submodel1: Submodel1 = Submodel1()
  @Published var submodel2: Submodel2 = Submodel2()
}

And this is the main view:

struct ContentView: View {
  @ObservedObject var model: Model = Model()

  var body: some View {
    VStack {
      Text("Count: \(model.submodel1.count)")
        .onTapGesture {
          self.model.submodel1.count += 1
        }
      Text("Count: \(model.submodel2.count)")
        .onTapGesture {
          self.model.submodel2.count += 1
        }
    }
  }
}

Adding this to the model class (see previous Stackoverflow question) works for updating on submodel1 changes, but not both:

  var anyCancellable: AnyCancellable? = nil
  init() {
      anyCancellable = submodel1.objectWillChange.sink { (_) in
          self.objectWillChange.send()
      }
   }

What I'm looking for is some way to pass on changes of both the submodel1 and submodel2 to my view.

like image 826
mxt533 Avatar asked Oct 17 '19 17:10

mxt533


1 Answers

You can expand upon the answer in the question you linked to by using CombineLatest to have your model fire its objectWillChange publisher when either of the underlying objects change:

import Combine

class Model: ObservableObject {
    @Published var submodel1: Submodel1 = Submodel1()
    @Published var submodel2: Submodel2 = Submodel2()

    var anyCancellable: AnyCancellable? = nil

    init() {
        anyCancellable = Publishers.CombineLatest(submodel1.$count,submodel2.$count).sink(receiveValue: {_ in
            self.objectWillChange.send()
        })
    }
}
like image 83
Paulw11 Avatar answered Nov 07 '22 21:11

Paulw11