0

So I am working on a view in SwiftUI which will update its state when an event is published.

The view looks like this:

struct MyView: View {
    
    @EnvironmentObject var dataSource: DataSource
    @State var data: [Model] = []
    

    func refreshData() {
        self.data = dataSource.getData()
    }
    
    var body: some View {
        VStack {
            List(self.data) { model in
                Row(model: model)
            }
        }
        .onAppear {
            self.refreshData()
        }
        .onReceive(self.dataSource.didUpdate) { _ in
            print("on receive")
            self.refreshData()
        }
    }
}

class DataSource: ObservableObject {
    var didUpdate: PassthroughSubject<Model,Never> ...
}

So with this setup, the onAppear block is called and works as expected. But the onReceive callback is never called. I have been able to verify that .send is being called correctly on the DataSource.didUpdate subject, but it appears the subscriber is not being notified.

Is there something I am missing to make this work?

sak
  • 2,612
  • 24
  • 55

1 Answers1

-1

As you are correctly declaring your DataSource as an observable object class, what you need now is to use the @Published property wrapper on you didUpdate variable. Then, with SwiftUI you can listen to it using .onChange(of:) { }. Just note that it does not work with computed vars: in such case, use the computed var to update the published var. Also, I assume you are correctly injecting your model instance in the environment (otherwise it will never work).

Like this:

struct MyView: View {
    
    @EnvironmentObject var dataSource: DataSource   // Remember to inject the specific instance in the environment
    @State var data: [Model] = []
    

    func refreshData() {
        self.data = dataSource.getData()
    }
    
    var body: some View {
        VStack {
            List(self.data) { model in
                Row(model: model)
            }
        }
        .onAppear {
            self.refreshData()
        }
//        .onReceive(self.dataSource.didUpdate) { _ in
//           print("on receive")
          .onChange(of: dataSource.didUpdate) { _ in     // Listen to changes in ObservableObject property that publishes
              print("on change")
              self.refreshData()
        }
    }
}

class DataSource: ObservableObject {

    // Note the property wrapper, but it does not work with computed vars:
    // in such case, use the computed var to update the published var.
    // Also: update it only in the main thread!
    @Published var didUpdate: PassthroughSubject<Model,Never> ...
}

HunterLion
  • 3,496
  • 1
  • 6
  • 18