Observer — un patron comportemental dans lequel un objet (l'éditeur) notifie plusieurs abonnés des changements de son état. Dans le développement mobile, Observer est à la base des mécanismes réactifs : l'UI s'abonne aux modifications de données et se met à jour automatiquement. Le patron est implémenté dans NotificationCenter sur iOS et LiveData/Flow sur Android. Plus de détails sur Refactoring Guru : Observer.
Points clés
Observer — un patron comportemental GoF qui définit une dépendance un-à-plusieurs entre objets. Lorsqu'un objet (Subject ou Observable) change d'état, tous les objets dépendants (Observers) sont automatiquement notifiés et mis à jour. Le patron implémente un couplage faible : l'éditeur ne connaît pas les classes spécifiques des abonnés — seulement qu'ils implémentent l'interface Observer.
Structure d'Observer comprend l'interface Subject avec les méthodes attach(), detach(), notify() et l'interface Observer avec la méthode update(). ConcreteSubject stocke l'état et la liste des abonnés. ConcreteObserver implémente update() et réagit aux changements. Dans le développement mobile, l'implémentation classique de GoF est rare — elle est remplacée par des mécanismes intégrés : NotificationCenter, Combine, Flow, LiveData, qui implémentent la même idée avec des API modernes.
Modèle Push vs Pull — dans le modèle Push, le Subject envoie des données à tous les abonnés (NotificationCenter.post). Dans le modèle Pull, le Subject notifie seulement et l'abonné demande les données lui-même. Android LiveData utilise Push (les données sont passées dans observe()), RxJava/Flow supportent les deux modèles. Le choix dépend de la tâche : Push est plus simple pour les mises à jour d'UI, Pull est plus efficace pour de grands volumes de données que l'abonné pourrait ne pas vouloir recevoir.
NotificationCenter — un mécanisme intégré iOS/macOS pour implémenter Observer. L'éditeur envoie une Notification via NotificationCenter.default.post(name:, object:, userInfo:). L'abonné s'enregistre via addObserver(forName:, queue:, using:). NotificationCenter supporte les notifications nommées (Notification.Name) et peut passer toutes données dans userInfo. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — exemples système.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Éditeur
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Abonné
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 }
// L'abonné réagit à l'événement
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Framework Combine — une alternative réactive moderne à NotificationCenter, introduite dans iOS 13. Publisher (NotificationCenter, URLSession, Timer) — l'éditeur, Subscriber (sink, assign) — l'abonné. Combine ajoute des opérateurs (map, filter, combineLatest) pour la transformation de flux de données. @Published — un property wrapper qui notifie automatiquement les abonnés des changements. Dans MVVM avec SwiftUI, Combine remplace NotificationCenter pour lier ViewModel et View.
KVO (Key-Value Observing) — un mécanisme plus ancien d'ObjC/Swift pour observer les propriétés individuelles d'objets. @objc dynamic var name: String — une propriété observable. observe(.name) — abonnement. KVO fonctionne uniquement avec les classes compatibles @objc et l'héritage ObjC. Apple recommande Combine et @Published plutôt que KVO dans les nouveaux projets. KVO reste pertinent pour la compatibilité UIKit dans les projets hybrides.
LiveData — un composant d'Android Architecture Components pour implémenter Observer. Une classe observable qui notifie les abonnés des changements de données. LiveData est conscient du cycle de vie : les abonnés (LifecycleOwner) se désabonnent automatiquement à la destruction. LiveData utilise le modèle Push : les données sont passées dans observe(). LiveData est le bloc de construction de base de MVVM sous Android avant Jetpack Compose.
// ViewModel — éditeur
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 — abonné
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// L'abonné réagit aux changements
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow et SharedFlow — des types réactifs de Kotlin Coroutines qui ont remplacé LiveData dans Jetpack Compose. StateFlow — un conteneur d'état observable avec une valeur actuelle fixe. SharedFlow — un flux hot configurable sans état, adapté aux événements uniques (navigation, toasts). Les deux types sont étroitement intégrés à Compose : collectAsState(), collectAsEffect(). StateFlow est obligatoire dans les projets Android modernes avec Compose.
LiveData vs StateFlow — LiveData est lié au cycle de vie Android, StateFlow est indépendant de la plateforme. StateFlow supporte les coroutines, les opérateurs (map, filter) et peut être testé sans dépendances Android. LiveData est plus simple pour la compatibilité Java. Google recommande StateFlow pour les nouveaux projets en Kotlin + Compose, LiveData pour la maintenance de projets existants ou de code Java.
Fuites mémoire — le principal problème d'Observer sans une gestion appropriée des abonnements. Si un abonné (Activity, Fragment, UIViewController) est détruit mais pas désabonné, l'éditeur continue de conserver une référence vers lui et le garbage collector ne peut pas libérer la mémoire. Sous Android, LifecycleOwner (Activity/Fragment) doit appeler removeObserver() ou utiliser observe(viewLifecycleOwner). Sous iOS — removeObserver dans deinit ou disposeBag dans Combine.
| Plateforme | Mécanisme Observer | Désabonnement automatique | Désabonnement manuel |
|---|---|---|---|
| iOS | NotificationCenter | Non | removeObserver() dans deinit |
| iOS | Combine (sink) | Non | store(in: &bag) — DisposeBag |
| iOS | KVO | Non | removeObserver() dans deinit |
| Android | LiveData | Oui (LifecycleOwner) | removeObserver() optionnel |
| Android | StateFlow | Via viewModelScope | cancel() Job au désabonnement |
| Android | RxJava | Non | dispose() dans CompositeDisposable |
Référence faible chez les abonnés — lors de l'utilisation de closures dans les blocs d'abonnement, utilisez [weak self] en Swift et référencez la portée du cycle de vie en Kotlin. LiveData gère automatiquement les abonnements via LifecycleOwner — l'abonnement n'est actif que lorsque le Lifecycle est dans l'état STARTED ou RESUMED. StateFlow dans Compose utilise collectAsState() avec conscience du cycle de vie. NotificationCenter sous iOS nécessite [weak self] explicite car la closure conserve une référence forte à self.
Observer (GoF) et Éditeur-Abonné (PubSub) — des patrons similaires mais différents. Dans Observer, l'éditeur notifie directement les abonnés en appelant leurs méthodes. L'éditeur connaît les abonnés (stocke une liste). Dans PubSub, l'éditeur et l'abonné ne se connaissent pas — un médiateur (Event Bus, Message Queue, NotificationCenter) se trouve entre eux. L'éditeur envoie un message sur un canal, l'abonné écoute le canal. PubSub a un couplage plus faible.
Exemples de PubSub dans le développement mobile — NotificationCenter sous iOS peut être considéré comme PubSub : l'éditeur ne connaît pas les abonnés — il publie simplement une notification. EventBus ou Otto sous Android (obsolètes). SharedFlow avec BroadcastChannel — PubSub dans le monde Kotlin. Dans les systèmes distribués, PubSub est implémenté via RabbitMQ, Kafka, Google PubSub. Pour le développement mobile, PubSub est utile dans une architecture modulaire où les modules ne doivent pas dépendre les uns des autres.
Que choisir — pour les mises à jour d'UI (ViewModel → View), utilisez Observer (LiveData, StateFlow, @Published). Pour les événements inter-modules (authentification, déconnexion, changement de thème) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer est plus simple et plus efficace au sein d'un même écran, PubSub est plus flexible pour les événements globaux mais plus difficile à déboguer en raison des dépendances implicites.
Questions fréquentes
StateFlow est un type indépendant de la plateforme de Kotlin Coroutines, tandis que LiveData est lié au cycle de vie Android. StateFlow supporte les coroutines et les opérateurs, et peut être testé sans Android. LiveData gère automatiquement les abonnements via LifecycleOwner. Google recommande StateFlow pour les nouveaux projets en Kotlin + Compose, et LiveData pour la compatibilité Java.
Utilisez [weak self] dans la closure du gestionnaire et appelez removeObserver() dans deinit. Stockez une référence à l'observateur (NSObjectProtocol) et supprimez-la lors de la destruction de l'objet. Dans Combine, utilisez AnyCancellable et store(in:) pour le désabonnement automatique lors de la libération du DisposeBag.
Oui, SwiftUI supporte ObservableObject avec @Published et @StateObject/@ObservedObject — c'est une implémentation intégrée d'Observer. @Published notifie automatiquement la View des changements. Combine n'est pas nécessaire : ObservableObject utilise le Publisher objectWillChange intégré à SwiftUI. Combine ajoute des opérateurs pour la transformation de flux.
SharedFlow — pour les événements uniques (navigation, toasts, Snackbar) où aucune valeur actuelle n'est nécessaire. StateFlow — pour l'état de l'UI (liste de données, progression du chargement) où un instantané actuel est nécessaire. SharedFlow n'a pas de propriété value et ne renvoie pas la dernière valeur aux nouveaux abonnés.
KVO est un mécanisme ObjC hérité, nécessite @objc dynamic et fonctionne uniquement avec les classes héritées de NSObject. Combine est un framework Swift moderne, type-safe, avec des opérateurs et une intégration avec SwiftUI. Combine remplace KVO et NotificationCenter. Apple recommande Combine pour les nouveaux projets, KVO uniquement pour la prise en charge héritée.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi