Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Observe internal changes in published object

Tags:

swiftui

SwiftUI, Swift 5.2, Xcode 11.4

I'm trying to observe changes in a singleton, but I'm not always getting my SwiftUI view refreshed:

final class Patient: ObservableObject {
      static var shared: Patient
      @Published var medicalData: MedicalData

      init { ... }

      final class MedicalData { 
            var allergies: String
            var ...

            init { ... }
      }
}

So, in my SwiftUI view:

struct ContentView: View {
       @ObservedObject var patient: Patient = Patient.shared
       var body: some view { ... }
}

If any object replaces the medical data, the publisher will inform my SwiftUI correctly:

patient.medicalData = NEW_MEDICAL_DATA --> OK! View refreshed

But if any object changes a value IN current medical data, the SwiftUI View is not refreshed:

patient.medicalData.allergies = "Alcanfor" --> NOT PUBLISHED

Does anyone knows how to accomplish this? Thank you in advance.

like image 311
AlbertUI Avatar asked May 10 '20 16:05

AlbertUI


People also ask

How do I observe a published object in SwiftUI?

You can use the @Published property wrapper to observe property changes inside any class. Any new values will be published from the willSet method meaning that we won't get the latest value when accessed directly.

How can an observable object announce changes to SwiftUI?

Classes that conform to the ObservableObject protocol can use SwiftUI's @Published property wrapper to automatically announce changes to properties, so that any views using the object get their body property reinvoked and stay in sync with their data.

What is ObservedObject?

A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes.

What is ObservableObject in Swift?

A type of object with a publisher that emits before the object has changed.


1 Answers

Found a elegant way to perform this (see didSet):

final class Patient: ObservableObject {
      static var shared: Patient
      @Published var medicalData = MedicalData() { 
           didSet {
                  subscription = medicalData.objectWillChange.sink { [weak self] _ in
                        self?.objectWillChange.send()
                  }
           }
      }
      var subscription: AnyCancellable?

      init { ... }
}

This works out of the box if the property was initialized. If not, just write also the didSet code after initialize the medicalData propertie at 'init()`.

Of course, MedicalData must conform the ObservableObject protocol.

like image 181
AlbertUI Avatar answered Nov 15 '22 07:11

AlbertUI