Observer — ein Verhaltensmuster, bei dem ein Objekt (der Publisher) mehrere Abonnenten über Änderungen seines Zustands benachrichtigt. In der mobilen Entwicklung bildet Observer die Grundlage reaktiver Mechanismen: Die UI abonniert Datenänderungen und aktualisiert sich automatisch. Das Muster ist in NotificationCenter unter iOS und LiveData/Flow unter Android implementiert. Weitere Details auf Refactoring Guru: Observer.
Wichtige Punkte
Observer — ein GoF-Verhaltensmuster, das eine Eins-zu-Viele-Abhängigkeit zwischen Objekten definiert. Wenn ein Objekt (Subject oder Observable) seinen Zustand ändert, werden alle abhängigen Objekte (Observers) automatisch benachrichtigt und aktualisiert. Das Muster implementiert lose Kopplung: Der Publisher kennt die spezifischen Klassen der Abonnenten nicht — nur, dass sie das Observer-Interface implementieren.
Observer-Struktur umfasst das Subject-Interface mit den Methoden attach(), detach(), notify() und das Observer-Interface mit der Methode update(). ConcreteSubject speichert den Zustand und die Abonnentenliste. ConcreteObserver implementiert update() und reagiert auf Änderungen. In der mobilen Entwicklung ist die klassische GoF-Implementierung selten — sie wird durch integrierte Mechanismen ersetzt: NotificationCenter, Combine, Flow, LiveData, die dieselbe Idee mit modernen APIs umsetzen.
Push vs Pull-Modell — im Push-Modell sendet das Subject Daten an alle Abonnenten (NotificationCenter.post). Im Pull-Modell benachrichtigt das Subject nur, und der Abonnent fordert die Daten selbst an. Android LiveData verwendet Push (Daten werden in observe() übergeben), RxJava/Flow unterstützen beide Modelle. Die Wahl hängt von der Aufgabe ab: Push ist einfacher für UI-Updates, Pull effizienter für große Datenmengen, die der Abonnent möglicherweise nicht empfangen möchte.
NotificationCenter — ein integrierter iOS/macOS-Mechanismus zur Implementierung von Observer. Der Publisher sendet eine Notification über NotificationCenter.default.post(name:, object:, userInfo:). Der Abonnent registriert sich über addObserver(forName:, queue:, using:). NotificationCenter unterstützt benannte Benachrichtigungen (Notification.Name) und kann beliebige Daten in userInfo übergeben. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — Systembeispiele.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Publisher
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Abonnent
class ProfileViewModel {
private var observers: [NSObjectProtocol] = []
func startObserving() {
let observer = NotificationCenter.default.addObserver(
forName: .userDidLogin,
object: nil,
queue: .main
) { [weak self] notification in
guard let userId = notification.userInfo?["userId"] as? String else { return }
// Abonnent reagiert auf das Ereignis
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Combine-Framework — eine moderne reaktive Alternative zu NotificationCenter, eingeführt in iOS 13. Publisher (NotificationCenter, URLSession, Timer) — der Herausgeber, Subscriber (sink, assign) — der Abonnent. Combine fügt Operatoren (map, filter, combineLatest) zur Datenstromtransformation hinzu. @Published — ein Property Wrapper, der Abonnenten automatisch über Änderungen benachrichtigt. In MVVM mit SwiftUI ersetzt Combine NotificationCenter zur Bindung von ViewModel und View.
KVO (Key-Value Observing) — ein älterer ObjC/Swift-Mechanismus zur Beobachtung einzelner Objekteigenschaften. @objc dynamic var name: String — eine beobachtbare Eigenschaft. observe(.name) — Abonnement. KVO funktioniert nur mit @objc-kompatiblen Klassen und ObjC-Vererbung. Apple empfiehlt Combine und @Published statt KVO in neuen Projekten. KVO bleibt für UIKit-Kompatibilität in Hybridprojekten relevant.
LiveData — eine Komponente der Android Architecture Components zur Implementierung von Observer. Eine beobachtbare Klasse, die Abonnenten über Datenänderungen benachrichtigt. LiveData ist lebenszyklusbewusst: Abonnenten (LifecycleOwner) melden sich bei Zerstörung automatisch ab. LiveData verwendet das Push-Modell: Daten werden in observe() übergeben. LiveData ist der grundlegende Baustein von MVVM in Android vor Jetpack Compose.
// ViewModel — Publisher
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User?>(null)
val user: LiveData<User?> = _user
fun loadUser(id: String) {
viewModelScope.launch {
val result = userRepository.getUser(id)
_user.value = result
}
}
}
// Fragment — Abonnent
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// Abonnent reagiert auf Änderungen
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow und SharedFlow — reaktive Typen aus Kotlin Coroutines, die LiveData in Jetpack Compose ersetzt haben. StateFlow — ein beobachtbarer Zustandshalter mit einem festen aktuellen Wert. SharedFlow — ein konfigurierbarer Hot Flow ohne Zustand, geeignet für einmalige Ereignisse (Navigation, Toasts). Beide Typen sind eng mit Compose integriert: collectAsState(), collectAsEffect(). StateFlow ist in modernen Android-Projekten mit Compose obligatorisch.
LiveData vs StateFlow — LiveData ist an den Android-Lebenszyklus gebunden, StateFlow ist plattformunabhängig. StateFlow unterstützt Coroutinen, Operatoren (map, filter) und kann ohne Android-Abhängigkeiten getestet werden. LiveData ist einfacher für Java-Kompatibilität. Google empfiehlt StateFlow für neue Projekte mit Kotlin + Compose, LiveData für die Wartung von Legacy-Projekten oder Java-Code.
Speicherlecks — das Hauptproblem von Observer ohne ordnungsgemäße Abonnementverwaltung. Wenn ein Abonnent (Activity, Fragment, UIViewController) zerstört wird, aber nicht abgemeldet ist, behält der Publisher weiterhin eine Referenz darauf, und der Garbage Collector kann den Speicher nicht freigeben. In Android sollte LifecycleOwner (Activity/Fragment) removeObserver() aufrufen oder observe(viewLifecycleOwner) verwenden. In iOS — removeObserver in deinit oder disposeBag in Combine.
| Plattform | Observer-Mechanismus | Automatische Abmeldung | Manuelle Abmeldung |
|---|---|---|---|
| iOS | NotificationCenter | Nein | removeObserver() in deinit |
| iOS | Combine (sink) | Nein | store(in: &bag) — DisposeBag |
| iOS | KVO | Nein | removeObserver() in deinit |
| Android | LiveData | Ja (LifecycleOwner) | removeObserver() optional |
| Android | StateFlow | Über viewModelScope | cancel() Job bei Abmeldung |
| Android | RxJava | Nein | dispose() in CompositeDisposable |
Schwache Referenz in Abonnenten — bei Verwendung von Closures in Abonnementblöcken verwenden Sie [weak self] in Swift und referenzieren Sie den Lebenszyklusbereich in Kotlin. LiveData verwaltet Abonnements automatisch über LifecycleOwner — das Abonnement ist nur aktiv, wenn der Lifecycle im Zustand STARTED oder RESUMED ist. StateFlow in Compose verwendet collectAsState() mit Lebenszyklusbewusstsein. NotificationCenter in iOS erfordert explizites [weak self], da die Closure eine starke Referenz auf self hält.
Observer (GoF) und Publisher-Subscriber (PubSub) — ähnliche, aber unterschiedliche Muster. Bei Observer benachrichtigt der Publisher Abonnenten direkt durch Aufruf ihrer Methoden. Der Publisher kennt die Abonnenten (speichert eine Liste). Bei PubSub kennen sich Publisher und Abonnent nicht — zwischen ihnen steht ein Vermittler (Event Bus, Message Queue, NotificationCenter). Der Publisher sendet eine Nachricht an einen Kanal, der Abonnent hört den Kanal ab. PubSub hat eine losere Kopplung.
Beispiele für PubSub in der mobilen Entwicklung — NotificationCenter in iOS kann als PubSub betrachtet werden: Der Publisher kennt die Abonnenten nicht — er veröffentlicht lediglich eine Benachrichtigung. EventBus oder Otto in Android (veraltet). SharedFlow mit BroadcastChannel — PubSub in der Kotlin-Welt. In verteilten Systemen wird PubSub über RabbitMQ, Kafka, Google PubSub implementiert. Für die mobile Entwicklung ist PubSub in modularer Architektur nützlich, wo Module nicht voneinander abhängen sollen.
Was wählen — für UI-Updates (ViewModel → View) verwenden Sie Observer (LiveData, StateFlow, @Published). Für modulübergreifende Ereignisse (Authentifizierung, Abmeldung, Themenwechsel) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer ist innerhalb eines Bildschirms einfacher und effizienter, PubSub ist flexibler für globale Ereignisse, aber aufgrund impliziter Abhängigkeiten schwieriger zu debuggen.
Häufig gestellte Fragen
StateFlow ist ein plattformunabhängiger Typ aus Kotlin Coroutines, während LiveData an den Android-Lebenszyklus gebunden ist. StateFlow unterstützt Coroutinen und Operatoren und kann ohne Android getestet werden. LiveData verwaltet Abonnements automatisch über LifecycleOwner. Google empfiehlt StateFlow für neue Projekte mit Kotlin + Compose und LiveData für Java-Kompatibilität.
Verwenden Sie [weak self] im Handler-Closure und rufen Sie removeObserver() in deinit auf. Speichern Sie eine Referenz auf den Observer (NSObjectProtocol) und entfernen Sie sie bei Zerstörung des Objekts. Verwenden Sie in Combine AnyCancellable und store(in:) zur automatischen Abmeldung bei Freigabe des DisposeBag.
Ja, SwiftUI unterstützt ObservableObject mit @Published und @StateObject/@ObservedObject — dies ist eine integrierte Observer-Implementierung. @Published benachrichtigt die View automatisch über Änderungen. Combine ist nicht erforderlich: ObservableObject verwendet den in SwiftUI integrierten objectWillChange Publisher. Combine fügt Operatoren zur Streamtransformation hinzu.
SharedFlow — für einmalige Ereignisse (Navigation, Toasts, Snackbar), bei denen kein aktueller Wert benötigt wird. StateFlow — für den UI-Zustand (Datenliste, Ladevorgang), bei dem eine aktuelle Momentaufnahme benötigt wird. SharedFlow hat keine value-Eigenschaft und gibt den letzten Wert nicht an neue Abonnenten zurück.
KVO ist ein älterer ObjC-Mechanismus, erfordert @objc dynamic und funktioniert nur mit Klassen, die von NSObject erben. Combine ist ein modernes Swift-Framework, typsicher, mit Operatoren und SwiftUI-Integration. Combine ersetzt KVO und NotificationCenter. Apple empfiehlt Combine für neue Projekte, KVO nur für Legacy-Unterstützung.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch