Observer — concetti chiave del pattern di sottoscrizione ai cambiamenti

Autore: IT Sectr Pubblicato: 2026-02-17 Tempo di lettura: 7 min

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 di sottoscrizione: un editore, molti sottoscrittori
  • NotificationCenter — implementazione integrata di Observer in iOS/macOS
  • Flow e LiveData — implementazioni reattive di Observer in Android
  • Push vs Pull — l'editore può inviare dati o notificare eventi
  • Perdite di memoria — i sottoscrittori devono annullare la sottoscrizione per evitare perdite

Cos'è Observer: l'essenza del pattern osservatore

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.

Observer in iOS: NotificationCenter, Combine e KVO

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.

swift
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.

Observer in Android: LiveData, StateFlow e SharedFlow

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.

kotlin
// 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.

Gestione delle sottoscrizioni e perdite di memoria

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.

PiattaformaMeccanismo ObserverAnnullamento automaticoAnnullamento manuale
iOSNotificationCenterNoremoveObserver() in deinit
iOSCombine (sink)Nostore(in: &bag) — DisposeBag
iOSKVONoremoveObserver() in deinit
AndroidLiveDataSì (LifecycleOwner)removeObserver() opzionale
AndroidStateFlowTramite viewModelScopecancel() Job all'annullamento
AndroidRxJavaNodispose() 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 vs Editore-Sottoscrittore: differenze

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

Qual è la differenza tra StateFlow e LiveData?

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.

Come evitare perdite di memoria con NotificationCenter?

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.

Si può usare Observer in SwiftUI senza Combine?

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.

Quando usare SharedFlow invece di StateFlow?

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.

Qual è la differenza tra KVO e Combine in iOS?

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

  • Observer — un pattern comportamentale per notificare i sottoscrittori dei cambiamenti
  • iOS NotificationCenter — implementazione PubSub con notifiche nominate
  • iOS Combine — un framework reattivo con Publisher e Subscriber
  • Android LiveData — Observer consapevole del ciclo di vita di Android Architecture Components
  • Android StateFlow — un contenitore di stato reattivo per Compose e coroutine
  • Gestione della memoria — annullamento obbligatorio della sottoscrizione per prevenire perdite
  • Observer vs PubSub — sottoscrizione diretta vs mediatore per accoppiamento debole

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.

Discuti il progetto

Leggi anche