Kurz zusammengefasst: ObservableObject

  • Mit dem Property-Wrapper @Published-ausgezeichnete Eigenschaften sind als Combine-Publisher einzeln beobachtbar (Eigenschaft xyz kann als $xyz via Combine abonniert werden)

  • Mit @Published deklarierte Eigeschaften lösen eine Benachrichtigung des objectWillChange-Publishers des Objektes aus

  • Wird ein ObservableObject in SwiftUI als @StateObject, @ObservedObject oder @EnvironmentObject verwendet, erfolgt automatisch eine Aktualisierung des Views bei Änderungen an @Published-Eigenschaften.

Beispiel:

class CounterModel: ObservableObject {
    @Published var value = 0

    func increment() {
        self.value += 1
    }
}

struct ContentView: View {
    @StateObject var counterModel = CounterModel()

    var body: some View {
        VStack {
            Text("Counter value \(self.counterModel.value)")
                .padding()

            Button("Increment") {
                self.counterModel.increment()
            }
        }
    }
}

Stolperfallen

  • Es heißt objectWillChange: Die Benachrichtigung erfolgt, bevor der neue Wert gesetzt wird (u.U. ungünstig wenn mehrere Werte in Kombination abonniert werden sollen - ObservableObject ist super für SwiftUI-"auto refresh" aber eher nicht für komplexere "reactive data flows")

  • Wenn ein ObservableObject Eigenschaften enthält, die als class deklariert sind (Referenz-Semantik), erfolgt nur eine Änderungsbenachrichtigung wenn sich die Referenz ändert, nicht die Inhalte des referenzierten Objektes.
    Empfehlung: Ausschließlich struct/enum-Typen für Eigenschaften verwenden

  • Vererbung funktioniert erst ab iOS 14.5 korrekt:
    @Published property wrapper not working on subclass of ObservableObject

  • Es gibt eine Möglichkeit, ObservableObjects ineinander zu verschachteln und eine rekursive Änderungsbenachrichtigung zu implementieren (Empfehlung: eher nicht):
    Nested ObservableObjects