Observer — un pattern comportamentale in cui un oggetto (l'editore) notifica a più sottoscrittori i cambiamenti del proprio stato. Nello sviluppo mobile, Observer è alla base dei meccanismi reattivi: la UI si sottoscrive ai cambiamenti dei dati e si aggiorna automaticamente. Il pattern è implementato in NotificationCenter su iOS e LiveData/Flow su Android. Maggiori dettagli su Refactoring Guru: Observer.
Punti chiave
Observer — un pattern comportamentale GoF che definisce una dipendenza uno-a-molti tra oggetti. Quando un oggetto (Subject o Observable) cambia stato, tutti gli oggetti dipendenti (Observers) vengono automaticamente notificati e aggiornati. Il pattern implementa un accoppiamento debole: l'editore non conosce le classi specifiche dei sottoscrittori — solo che implementano l'interfaccia Observer.
Struttura di Observer include l'interfaccia Subject con i metodi attach(), detach(), notify() e l'interfaccia Observer con il metodo update(). ConcreteSubject memorizza lo stato e la lista dei sottoscrittori. ConcreteObserver implementa update() e reagisce ai cambiamenti. Nello sviluppo mobile, l'implementazione classica di GoF è rara — viene sostituita da meccanismi integrati: NotificationCenter, Combine, Flow, LiveData, che implementano la stessa idea con API moderne.
Modello Push vs Pull — nel modello Push, il Subject invia dati a tutti i sottoscrittori (NotificationCenter.post). Nel modello Pull, il Subject notifica solo e il sottoscrittore richiede i dati da solo. Android LiveData usa Push (i dati vengono passati in observe()), RxJava/Flow supportano entrambi i modelli. La scelta dipende dal compito: Push è più semplice per gli aggiornamenti UI, Pull è più efficiente per grandi volumi di dati che il sottoscrittore potrebbe non voler ricevere.
NotificationCenter — un meccanismo integrato iOS/macOS per implementare Observer. L'editore invia una Notification tramite NotificationCenter.default.post(name:, object:, userInfo:). Il sottoscrittore si registra tramite addObserver(forName:, queue:, using:). NotificationCenter supporta notifiche nominate (Notification.Name) e può passare qualsiasi dato in userInfo. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — esempi di sistema.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Editore
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Sottoscrittore
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 }
// Il sottoscrittore reagisce all'evento
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Framework Combine — un'alternativa reattiva moderna a NotificationCenter, introdotta in iOS 13. Publisher (NotificationCenter, URLSession, Timer) — l'editore, Subscriber (sink, assign) — il sottoscrittore. Combine aggiunge operatori (map, filter, combineLatest) per la trasformazione dei flussi di dati. @Published — un property wrapper che notifica automaticamente i sottoscrittori dei cambiamenti. In MVVM con SwiftUI, Combine sostituisce NotificationCenter per collegare ViewModel e View.
KVO (Key-Value Observing) — un meccanismo più vecchio di ObjC/Swift per osservare singole proprietà degli oggetti. @objc dynamic var name: String — una proprietà osservabile. observe(.name) — sottoscrizione. KVO funziona solo con classi compatibili @objc e ereditarietà ObjC. Apple raccomanda Combine e @Published invece di KVO nei nuovi progetti. KVO rimane rilevante per la compatibilità UIKit in progetti ibridi.
LiveData — un componente di Android Architecture Components per implementare Observer. Una classe osservabile che notifica ai sottoscrittori i cambiamenti dei dati. LiveData è consapevole del ciclo di vita: i sottoscrittori (LifecycleOwner) si annullano automaticamente alla distruzione. LiveData usa il modello Push: i dati vengono passati in observe(). LiveData è il mattone fondamentale di MVVM in Android prima di Jetpack Compose.
// ViewModel — editore
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 — sottoscrittore
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// Il sottoscrittore reagisce ai cambiamenti
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow e SharedFlow — tipi reattivi di Kotlin Coroutines che hanno sostituito LiveData in Jetpack Compose. StateFlow — un contenitore di stato osservabile con un valore corrente fisso. SharedFlow — un flusso hot configurabile senza stato, adatto per eventi una tantum (navigazione, toast). Entrambi i tipi sono strettamente integrati con Compose: collectAsState(), collectAsEffect(). StateFlow è obbligatorio nei progetti Android moderni con Compose.
LiveData vs StateFlow — LiveData è legato al ciclo di vita Android, StateFlow è indipendente dalla piattaforma. StateFlow supporta coroutine, operatori (map, filter) e può essere testato senza dipendenze Android. LiveData è più semplice per la compatibilità Java. Google raccomanda StateFlow per i nuovi progetti in Kotlin + Compose, LiveData per la manutenzione di progetti legacy o codice Java.
Perdite di memoria — il problema principale di Observer senza una corretta gestione delle sottoscrizioni. Se un sottoscrittore (Activity, Fragment, UIViewController) viene distrutto ma non annulla la sottoscrizione, l'editore continua a mantenere un riferimento ad esso e il garbage collector non può liberare la memoria. In Android, LifecycleOwner (Activity/Fragment) deve chiamare removeObserver() o usare observe(viewLifecycleOwner). In iOS — removeObserver in deinit o disposeBag in Combine.
| Piattaforma | Meccanismo Observer | Annullamento automatico | Annullamento manuale |
|---|---|---|---|
| iOS | NotificationCenter | No | removeObserver() in deinit |
| iOS | Combine (sink) | No | store(in: &bag) — DisposeBag |
| iOS | KVO | No | removeObserver() in deinit |
| Android | LiveData | Sì (LifecycleOwner) | removeObserver() opzionale |
| Android | StateFlow | Tramite viewModelScope | cancel() Job all'annullamento |
| Android | RxJava | No | dispose() in CompositeDisposable |
Riferimento debole nei sottoscrittori — quando si usano closure nei blocchi di sottoscrizione, usa [weak self] in Swift e fai riferimento all'ambito del ciclo di vita in Kotlin. LiveData gestisce automaticamente le sottoscrizioni tramite LifecycleOwner — la sottoscrizione è attiva solo quando il Lifecycle è nello stato STARTED o RESUMED. StateFlow in Compose usa collectAsState() con consapevolezza del ciclo di vita. NotificationCenter in iOS richiede [weak self] esplicito perché la closure mantiene un riferimento forte a self.
Observer (GoF) e Editore-Sottoscrittore (PubSub) — pattern simili ma diversi. In Observer, l'editore notifica direttamente i sottoscrittori chiamando i loro metodi. L'editore conosce i sottoscrittori (memorizza una lista). In PubSub, editore e sottoscrittore non si conoscono — un mediatore (Event Bus, Message Queue, NotificationCenter) si trova tra di loro. L'editore invia un messaggio a un canale, il sottoscrittore ascolta il canale. PubSub ha un accoppiamento più debole.
Esempi di PubSub nello sviluppo mobile — NotificationCenter in iOS può essere considerato PubSub: l'editore non conosce i sottoscrittori — pubblica semplicemente una notifica. EventBus o Otto in Android (obsoleti). SharedFlow con BroadcastChannel — PubSub nel mondo Kotlin. Nei sistemi distribuiti, PubSub è implementato tramite RabbitMQ, Kafka, Google PubSub. Per lo sviluppo mobile, PubSub è utile in architettura modulare dove i moduli non devono dipendere l'uno dall'altro.
Cosa scegliere — per gli aggiornamenti UI (ViewModel → View), usa Observer (LiveData, StateFlow, @Published). Per eventi tra moduli (autenticazione, logout, cambio tema) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer è più semplice ed efficiente all'interno di un singolo schermo, PubSub è più flessibile per eventi globali ma più difficile da debuggare a causa di dipendenze implicite.
Domande frequenti
StateFlow è un tipo indipendente dalla piattaforma di Kotlin Coroutines, mentre LiveData è legato al ciclo di vita Android. StateFlow supporta coroutine e operatori, e può essere testato senza Android. LiveData gestisce automaticamente le sottoscrizioni tramite LifecycleOwner. Google raccomanda StateFlow per i nuovi progetti in Kotlin + Compose, e LiveData per la compatibilità Java.
Usa [weak self] nella closure del gestore e chiama removeObserver() in deinit. Conserva un riferimento all'observer (NSObjectProtocol) e rimuovilo quando l'oggetto viene distrutto. In Combine, usa AnyCancellable e store(in:) per l'annullamento automatico al rilascio del DisposeBag.
Sì, SwiftUI supporta ObservableObject con @Published e @StateObject/@ObservedObject — questa è un'implementazione integrata di Observer. @Published notifica automaticamente la View dei cambiamenti. Combine non è necessario: ObservableObject usa il Publisher objectWillChange integrato in SwiftUI. Combine aggiunge operatori per la trasformazione dei flussi.
SharedFlow — per eventi una tantum (navigazione, toast, Snackbar) dove non serve un valore corrente. StateFlow — per lo stato UI (elenco dati, progresso caricamento) dove serve un'istantanea corrente. SharedFlow non ha una proprietà value e non restituisce l'ultimo valore ai nuovi sottoscrittori.
KVO è un meccanismo ObjC legacy, richiede @objc dynamic e funziona solo con classi ereditate da NSObject. Combine è un framework Swift moderno, type-safe, con operatori e integrazione SwiftUI. Combine sostituisce KVO e NotificationCenter. Apple raccomanda Combine per i nuovi progetti, KVO solo per il supporto legacy.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche