Observer — een gedragspatroon waarbij een object (uitgever) meerdere abonnees op de hoogte stelt van veranderingen in zijn toestand. In mobiele ontwikkeling vormt Observer de basis van reactieve mechanismen: UI abonneert zich op gegevenswijzigingen en werkt automatisch bij. Het patroon is geïmplementeerd in NotificationCenter op iOS en LiveData/Flow op Android. Meer — op Refactoring Guru: Observer.
Belangrijkste punten
Observer (observator) — een GoF-gedragspatroon dat een «een-op-veel»-afhankelijkheid tussen objecten definieert. Wanneer een object (Subject of Observable) van toestand verandert, worden alle afhankelijke objecten (Observers) automatisch op de hoogte gesteld en bijgewerkt. Het patroon implementeert losse koppeling: de uitgever kent de concrete klassen van abonnees niet — alleen dat ze de Observer-interface implementeren.
Observer-structuur omvat de Subject-interface met methoden attach(), detach(), notify() en de Observer-interface met de methode update(). ConcreteSubject slaat de toestand en de lijst van abonnees op. ConcreteObserver implementeert update() en reageert op wijzigingen. In mobiele ontwikkeling komt de klassieke GoF-implementatie zelden voor — deze wordt vervangen door ingebouwde mechanismen: NotificationCenter, Combine, Flow, LiveData, die hetzelfde idee met een moderne API implementeren.
Push vs Pull-model — in het Push-model stuurt Subject gegevens naar alle abonnees (NotificationCenter.post). In het Pull-model stelt Subject alleen op de hoogte en haalt de abonnee zelf de gegevens op. Android LiveData gebruikt Push (gegevens worden doorgegeven in observe()), RxJava/Flow ondersteunen beide modellen. De keuze hangt af van de taak: Push is eenvoudiger voor UI-updates, Pull is efficiënter voor grote hoeveelheden gegevens die de abonnee mogelijk niet wil ontvangen.
NotificationCenter — het ingebouwde iOS/macOS-mechanisme voor het implementeren van Observer. De uitgever verzendt Notification via NotificationCenter.default.post(name:, object:, userInfo:). De abonnee registreert zich via addObserver(forName:, queue:, using:). NotificationCenter ondersteunt benoemde meldingen (Notification.Name) en kan elke gegevens in userInfo doorgeven. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — systeemvoorbeelden.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Uitgever
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Abonnee
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 }
// Abonnee reageert op gebeurtenis
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Combine framework — een modern reactief alternatief voor NotificationCenter, beschikbaar sinds iOS 13. Publisher (NotificationCenter, URLSession.Timer) — uitgever, Subscriber (sink, assign) — abonnee. Combine voegt operatoren (map, filter, combineLatest) toe voor transformatie van de gegevensstroom. @Published — property wrapper die abonnees automatisch op de hoogte stelt van wijzigingen. In MVVM met SwiftUI vervangt Combine NotificationCenter voor het koppelen van ViewModel en View.
KVO (Key-Value Observing) — een oud ObjC/Swift-mechanisme voor het observeren van individuele eigenschappen van objecten. @objc dynamic var name: String — geobserveerde eigenschap. observe(.name) — abonnement. KVO werkt alleen met @objc-compatibele klassen en ObjC-overerving. Apple beveelt Combine en @Published aan in plaats van KVO in nieuwe projecten. KVO blijft relevant voor UIKit-compatibiliteit in hybride projecten.
LiveData — een Android Architecture Components-component voor het implementeren van Observer. Een Observable-klasse die abonnees op de hoogte stelt van gegevenswijzigingen. LiveData houdt rekening met de levenscyclus: abonnees (LifecycleOwner) schrijven zich automatisch uit bij vernietiging. LiveData is het Push-model: gegevens worden doorgegeven in observe(). LiveData is de basisbouwsteen van MVVM in Android vóór de introductie van Jetpack Compose.
// ViewModel — uitgever
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 — abonnee
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// Abonnee reageert op wijzigingen
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow en SharedFlow — reactieve typen uit Kotlin Coroutines die LiveData in Jetpack Compose hebben vervangen. StateFlow — observable state holder met een vaste huidige waarde. SharedFlow — configureerbare hot flow zonder toestand, geschikt voor eenmalige gebeurtenissen (navigatie, toasts). Beide typen zijn nauw geïntegreerd met Compose: collectAsState(), collectAsEffect(). StateFlow is verplicht in moderne Android-projecten met Compose.
LiveData vs StateFlow — LiveData is gebonden aan Android Lifecycle, StateFlow is platformonafhankelijk. StateFlow ondersteunt coroutines, operatoren (map, filter) en wordt getest zonder Android-afhankelijkheden. LiveData is eenvoudiger voor Java-compatibiliteit. Google beveelt StateFlow aan voor nieuwe projecten met Kotlin + Compose, LiveData — voor ondersteuning van oude projecten of Java-code.
Geheugenlekken (memory leaks) — het belangrijkste probleem van Observer zonder correct abonnementenbeheer. Als een abonnee (Activity, Fragment, UIViewController) is vernietigd maar niet is uitgeschreven, blijft de uitgever een verwijzing ernaar behouden en kan de garbage collector het geheugen niet vrijgeven. In Android moet LifecycleOwner (Activity/Fragment) removeObserver() aanroepen of observe(viewLifecycleOwner) gebruiken. In iOS — removeObserver in deinit of disposeBag in Combine.
| Platform | Observer-mechanisme | Automatisch uitschrijven | Handmatig uitschrijven |
|---|---|---|---|
| iOS | NotificationCenter | Nee | removeObserver() in deinit |
| iOS | Combine (sink) | Nee | store(in: &bag) — DisposeBag |
| iOS | KVO | Nee | removeObserver() in deinit |
| Android | LiveData | Ja (LifecycleOwner) | removeObserver() optioneel |
| Android | StateFlow | Via viewModelScope | cancel() Job bij uitschrijven |
| Android | RxJava | Nee | dispose() in CompositeDisposable |
Zwakke verwijzing (weak reference) in abonnees — gebruik in het abonnementsblok [weak self] in Swift en verwijs naar lifecycle scope in Kotlin. LiveData beheert het abonnement automatisch via LifecycleOwner — het abonnement is alleen actief wanneer Lifecycle in de status STARTED of RESUMED is. StateFlow in Compose gebruikt collectAsState() met inachtneming van lifecycle. NotificationCenter in iOS vereist expliciet [weak self], omdat de closure sterk naar self verwijst.
Observer (GoF) en Publisher-Subscriber (PubSub) — vergelijkbare maar verschillende patronen. In Observer stelt de uitgever abonnees direct op de hoogte door hun methoden aan te roepen. De uitgever weet van abonnees (slaat een lijst op). In PubSub weten de uitgever en abonnee niet van elkaar — er is een tussenpersoon (Event Bus, Message Queue, NotificationCenter). De uitgever stuurt een bericht naar een kanaal, de abonnee luistert naar het kanaal. PubSub zorgt voor lossere koppeling.
Voorbeelden van PubSub in mobiele ontwikkeling — NotificationCenter in iOS kan als PubSub worden beschouwd: de uitgever kent abonnees niet — hij plaatst gewoon een melding. EventBus of Otto in Android (verouderd). SharedFlow met BroadcastChannel — PubSub in de Kotlin-wereld. In gedistribueerde systemen wordt PubSub geïmplementeerd via RabbitMQ, Kafka, Google PubSub. Voor mobiele ontwikkeling is PubSub nuttig in modulaire architectuur, waar modules niet van elkaar afhankelijk mogen zijn.
Wat te kiezen — voor UI-updates (ViewModel → View) gebruik Observer (LiveData, StateFlow, @Published). Voor intermodule-gebeurtenissen (autorisatie, uitloggen, themawijziging) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer is eenvoudiger en efficiënter binnen één scherm, PubSub is flexibeler voor globale gebeurtenissen maar moeilijker te debuggen vanwege impliciete afhankelijkheden.
Veelgestelde vragen
StateFlow is een platformonafhankelijk type uit Kotlin Coroutines, LiveData is gebonden aan Android Lifecycle. StateFlow ondersteunt coroutines en operatoren, wordt getest zonder Android. LiveData beheert het abonnement automatisch via LifecycleOwner. Google beveelt StateFlow aan voor nieuwe projecten met Kotlin + Compose, LiveData — voor Java-compatibiliteit.
Gebruik [weak self] in de handler-closure en roep removeObserver() aan in deinit. Bewaar een verwijzing naar de observer (NSObjectProtocol) en verwijder deze bij vernietiging van het object. Gebruik in Combine AnyCancellable en store(in:) voor automatisch uitschrijven bij het vrijgeven van DisposeBag.
Ja, SwiftUI ondersteunt ObservableObject met @Published en @StateObject/@ObservedObject — dit is een ingebouwde implementatie van Observer. @Published stelt View automatisch op de hoogte van wijzigingen. Combine is niet vereist: ObservableObject gebruikt de in SwiftUI ingebouwde objectWillChange Publisher. Combine voegt operatoren toe voor stroomtransformatie.
SharedFlow — voor eenmalige gebeurtenissen (navigatie, toasts, Snackbar) waar geen huidige waarde nodig is. StateFlow — voor UI-status (gegevenslijst, laadvoortgang) waar een huidige snapshot nodig is. SharedFlow heeft geen value-eigenschap en retourneert de laatste waarde niet aan nieuwe abonnees.
KVO is een verouderd ObjC-mechanisme, vereist @objc dynamic en werkt alleen met klassen die overerven van NSObject. Combine is een modern Swift-framework, typeveilig, met operatoren en integratie met SwiftUI. Combine vervangt KVO en NotificationCenter. Apple beveelt Combine aan voor nieuwe projecten, KVO — alleen voor ondersteuning van verouderde code.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook