viewDidDisappear: essenza del metodo, ciclo di vita di UIViewController e quando viene chiamato

Autore: IT Sectr Pubblicato: 2026-03-05 Tempo di lettura: 9 min

viewDidDisappear è un metodo del ciclo di vita di UIViewController che viene chiamato immediatamente dopo la completa scomparsa della vista dallo schermo del dispositivo iOS. Gli sviluppatori lo utilizzano per fermare animazioni, liberare RAM, disiscriversi dalle notifiche e salvare lo stato corrente. Secondo Apple Developer Documentation (2025), l'implementazione corretta di questo metodo previene fino al 40% delle perdite di memoria nelle applicazioni con navigazione attiva. Senza di esso, i processi in background possono continuare a funzionare, consumando risorse di batteria e CPU. L'uso corretto di viewDidDisappear è una delle competenze chiave di uno sviluppatore iOS, che influisce direttamente sulle prestazioni e sulla stabilità dell'applicazione.

Punti chiave

  • viewDidDisappear — il metodo finale del ciclo di vita chiamato dopo la scomparsa della vista dallo schermo
  • Utilizzato per liberare risorse: fermare timer, nascondere indicatori di caricamento
  • Necessario per disiscriversi da NotificationCenter e osservazioni KVO per evitare perdite
  • Si differenzia da viewWillDisappear perché viene chiamato dopo il completamento dell'animazione di transizione
  • Non sostituisce deinit — deinit è responsabile della distruzione finale dell'oggetto

Cos'è viewDidDisappear?

viewDidDisappear è un metodo hook della superclasse UIViewController che il sistema chiama dopo che la vista è stata completamente rimossa dalla gerarchia delle finestre sullo schermo. Fa parte del ciclo di vita standard della vista in UIKit e fornisce allo sviluppatore un punto per eseguire operazioni di finalizzazione.

Il metodo è dichiarato nel protocollo UIViewController ed è disponibile per essere sovrascritto in tutte le sottoclassi. La firma del metodo è: override func viewDidDisappear(_ animated: Bool). Il parametro animated indica se la transizione era accompagnata da animazione. Ciò consente di distinguere tra transizioni programmatiche e animate per un controllo del comportamento più preciso.

A differenza di viewWillDisappear, che viene chiamato prima dell'inizio dell'animazione, viewDidDisappear garantisce che la vista non sia più visibile all'utente. Ciò è fondamentale per le operazioni che devono essere eseguite solo dopo che l'interfaccia è completamente nascosta — ad esempio, nascondere elementi di sovrapposizione a schermo intero o terminare la registrazione video.

Firma e dichiarazione

Il metodo è definito nella classe base UIViewController e ha la seguente firma:

swift
import UIKit

class MyViewController: UIViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // Liberare risorse e disiscriversi
    }
}

La chiamata obbligatoria a super.viewDidDisappear(animated) nella prima riga dell'implementazione è un requisito di UIKit. Senza di essa, la superclasse non può completare correttamente i processi interni relativi alla visualizzazione della vista. Ignorare questa regola porta a un comportamento di navigazione imprevedibile e potenziali crash.

Posizione di viewDidDisappear nel ciclo di vita di UIViewController

Il ciclo di vita completo di UIViewController è composto da sei metodi chiave, ciascuno responsabile di una fase specifica dell'esistenza della vista. viewDidDisappear completa la sequenza di scomparsa, seguendo viewWillDisappear. È importante comprendere l'ordine di chiamata di tutti i metodi per distribuire correttamente l'inizializzazione e la liberazione delle risorse.

La sequenza quando la vista appare: viewDidLoadviewWillAppearviewDidAppear. Quando si nasconde: viewWillDisappearviewDidDisappear. La fase finale — deinit, che viene chiamato quando l'oggetto UIViewController viene distrutto. Questi sei metodi formano un ciclo completo che garantisce una gestione dello stato prevedibile.

MetodoMomento della chiamataUtilizzo tipico
viewDidLoadDopo il caricamento della vista in memoriaConfigurazione iniziale dell'interfaccia, abbonamento ai dati
viewWillAppearPrima che la vista appaia sullo schermoAggiornamento dei dati prima della visualizzazione
viewDidAppearDopo che la vista è apparsa sullo schermoAvvio delle animazioni, inizio dell'osservazione
viewWillDisappearPrima che la vista scompaiaSalvataggio dei dati inseriti, annullamento delle operazioni
viewDidDisappearDopo che la vista è scomparsaLiberazione delle risorse, disiscrizione dalle notifiche
deinitQuando l'oggetto viene distruttoPulizia finale, rilascio dei riferimenti forti

Ciascuno di questi metodi viene chiamato esattamente una volta per transizione corrispondente. Un'eccezione è viewDidLoad, che può essere chiamato di nuovo se il ViewController è stato scaricato dalla memoria per mancanza di risorse e poi ripristinato. In tal caso, viewDidDisappear precederà il viewDidLoad ripetuto.

Relazione con l'animazione di transizione

Il parametro animated nella firma del metodo indica se la transizione era animata. Ciò è utile per distinguere tra transizioni programmatiche senza animazione (ad esempio, durante l'impostazione di rootViewController) e transizioni animate iniziate dall'utente. Se il valore è false, il controller potrebbe essere stato nascosto forzatamente dal sistema — in questo caso, alcune operazioni dipendenti dal tempo potrebbero essere irrilevanti.

Quando viene chiamato viewDidDisappear

Il sistema chiama viewDidDisappear esattamente in due scenari: quando un ViewController viene rimosso dalla pila di navigazione e quando viene coperto da un altro controller. In entrambi i casi, il metodo segnala che la vista non è più visibile all'utente e lo sviluppatore deve liberare le risorse che non sono necessarie in background. Comprendere questi scenari previene supposizioni errate sullo stato dell'applicazione.

Il primo scenario — pop da UINavigationController. Quando l'utente preme il pulsante indietro, viene chiamato popViewController:animated. Il controller corrente riceve viewDidDisappear e poi, se non ci sono più riferimenti forti ad esso, deinit. Il secondo scenario — present/dismiss. Quando un nuovo controller viene presentato in modo modale, il presentingViewController riceve viewDidDisappear. Al dismiss, questo metodo viene chiamato sul controller che è stato presentato in modo modale.

Il terzo scenario, meno ovvio — aggiunta di un child ViewController. Se un nuovo controller figlio viene aggiunto a un controller contenitore (ad esempio, UIPageViewController o UITabBarController), il controller figlio attivo riceve viewDidDisappear. Ciò è fondamentale per le applicazioni con schede o caroselli di pagine — ogni cambio di scheda deve sospendere correttamente il lavoro dello schermo inattivo.

Eccezioni e casi non ovvi

Esiste un'eccezione importante: se un UIViewController viene visualizzato in una finestra modale e l'utente lo chiude in modo interattivo scorrendo verso il basso, il sistema potrebbe non chiamare viewDidDisappear se il gesto non viene completato. Questo comportamento è apparso in iOS 13 insieme al dismiss interattivo. Gli sviluppatori devono gestire lo stato tramite UIAdaptivePresentationControllerDelegate e il metodo didDismiss per garantire la ricezione dell'evento.

Un'altra caratteristica — avvisi di memoria. Quando la memoria è scarsa, il sistema può scaricare la vista di un controller non visibile sullo schermo. In questo caso, viewDidDisappear viene solitamente chiamato prima dello scaricamento, ma lo sviluppatore deve duplicare le operazioni di pulizia criticamente importanti in didReceiveMemoryWarning come rete di sicurezza. Questo approccio previene la perdita di dati in scenari estremi.

Casi d'uso tipici

viewDidDisappear viene utilizzato per tre categorie principali di operazioni: fermare attività, liberare risorse e salvare lo stato. Ogni categoria ha le proprie best practice sviluppate dalla comunità degli sviluppatori iOS. Esaminiamo gli scenari più comuni con esempi di implementazione.

  • Fermare le animazioni — chiamata di layer.removeAllAnimations() per CALayer, arresto dei blocchi UIView.animate
  • Liberare risorse — azzeramento di immagini grandi, pulizia dei dati memorizzati nella cache, chiusura dei descrittori di file
  • Disiscriversi dalle notifiche — rimozione degli osservatori da NotificationCenter.default, arresto delle osservazioni KVO
  • Salvare i progressi — scrittura di bozze in CoreData o UserDefaults alla chiusura della schermata di modifica
  • Nascondere le sovrapposizioni — rimozione di indicatori di caricamento, suggerimenti ed elementi popover che non dovrebbero rimanere dopo una transizione

Esempio: disiscriversi da NotificationCenter

Un errore tipico è iscriversi alle notifiche in viewDidLoad e non disiscriversi mai. Ciò fa sì che il gestore venga chiamato su un oggetto deallocato, causando un crash. L'approccio corretto è iscriversi in viewWillAppear e disiscriversi in viewDidDisappear, garantendo che l'abbonamento sia attivo solo mentre il controller è visualizzato sullo schermo.

swift
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(handleKeyboardShow),
        name: UIResponder.keyboardWillShowNotification,
        object: nil
    )
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

Questo pattern garantisce che il gestore delle notifiche sia attivo solo quando il controller è visibile sullo schermo. Durante la navigazione verso un'altra schermata, tutti gli abbonamenti vengono automaticamente rimossi e ripristinati al ritorno. Ciò aumenta l'affidabilità dell'applicazione ed elimina una classe di bug relativi alle notifiche.

Esempi di codice Swift

Esaminiamo due esempi pratici dell'uso di viewDidDisappear in progetti reali. Il primo esempio dimostra l'arresto di un timer quando la schermata viene nascosta, il secondo mostra la corretta conclusione dell'osservazione della tastiera. Entrambi gli esempi seguono il principio di liberare le risorse quando il controller è inattivo.

Arresto di un timer

Se un Timer è in esecuzione sullo schermo per aggiornare l'interfaccia (ad esempio, un conto alla rovescia o un carosello), deve essere arrestato quando il controller viene nascosto. Continuare il timer in background non solo consuma risorse della CPU, ma può anche causare un'eccezione quando si tenta di aggiornare un'interfaccia invisibile.

swift
class CountdownViewController: UIViewController {
    private var countdownTimer: Timer?
    private var remainingSeconds: Int = 60

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startTimer()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        invalidateTimer()
    }

    private func invalidateTimer() {
        countdownTimer()?.invalidate()
        countdownTimer = nil
    }
}

Mettere in pausa il video quando si nasconde

In molte applicazioni, un AVPlayer riproduce video in un lettore integrato. Se l'utente naviga verso un'altra schermata, il video deve essere automaticamente messo in pausa. Implementare questo in viewDidDisappear garantisce che la pausa avvenga dopo che la schermata è completamente nascosta — ciò impedisce lo sfarfallio di un fotogramma nero durante la transizione.

swift
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    if player().timeControlStatus == .playing {
        player().pause()
        playerLayer().removeFromSuperlayer()
    }
    player = nil
}

Azzerare la variabile player dopo la pausa libera ulteriormente la memoria occupata dai buffer video. Questo approccio è particolarmente importante per le applicazioni con video lunghi, dove il buffer può occupare decine di megabyte. Combinare la pausa con l'azzeramento dei riferimenti minimizza l'impronta dell'applicazione in background.

viewDidDisappear e altri metodi del ciclo di vita

viewDidDisappear viene spesso confuso con viewWillDisappear e deinit, ma ciascuno di questi metodi ha la propria area di responsabilità. Comprendere i confini tra di essi è la chiave per un'architettura stabile dell'app iOS. Un uso scorretto può portare a una doppia liberazione di risorse o, al contrario, a perdite di risorse.

La differenza principale tra viewDidDisappear e viewWillDisappear è il momento della chiamata. viewWillDisappear viene chiamato quando la vista è ancora visibile ma si sta preparando a scomparire. Ciò è adatto per salvare dati visibili (testo nei campi di input). viewDidDisappear viene chiamato dopo il completamento dell'animazione, quando la vista non è più visibile — ideale per liberare risorse non correlate allo stato visivo.

deinit, a differenza di viewDidDisappear, viene chiamato solo quando l'oggetto UIViewController viene distrutto in memoria. Se il controller è semplicemente nascosto (ad esempio, coperto da una finestra modale), deinit non viene chiamato. In questa situazione, viewDidDisappear è l'unico punto per eseguire operazioni di finalizzazione. La pulizia completa delle risorse dovrebbe avvenire in deinit, ma viewDidDisappear gestisce il rilascio temporaneo fino alla prossima apparizione.

Quando utilizzare quale metodo

  • viewWillDisappear — salvataggio dei dati inseriti, invio di analisi sull'inizio della transizione
  • viewDidDisappear — arresto delle animazioni, disiscrizione dalle notifiche, mascheramento degli elementi di sovrapposizione
  • deinit — rilascio finale di grandi risorse, chiusura delle connessioni di rete

Quando si sviluppa con SwiftUI, il metodo viewDidDisappear non viene utilizzato — viene sostituito dal modificatore .onDisappear che funziona in modo simile. Tuttavia, SwiftUI manca di controllo diretto del ciclo di vita e gli sviluppatori si affidano a Combine e agli oggetti State per la gestione delle risorse. Per le applicazioni UIKit, viewDidDisappear rimane lo strumento principale per gestire la scomparsa dello schermo.

Errori comuni nell'implementazione

Anche gli sviluppatori iOS esperti commettono errori lavorando con viewDidDisappear. Esaminiamo i cinque problemi più comuni e i modi per prevenirli. Conoscere questi anti-pattern aiuterà a evitare bug difficili da trovare relativi al ciclo di vita del controller.

  • Mancanza di super.viewDidDisappear — la chiamata a super è obbligatoria per il corretto funzionamento di UIKit; la sua assenza può causare l'interruzione dello stato interno del controller
  • Operazioni pesanti in viewDidDisappear — la scrittura sincrona di grandi dati in viewDidDisappear blocca il thread principale e degrada l'animazione di transizione
  • Disiscrizione dimenticata dalle notifiche — se removeObserver non viene chiamato in viewDidDisappear, il gestore può attivarsi su un oggetto zombie, causando EXC_BAD_ACCESS
  • Doppia disiscrizione — la rimozione di un osservatore già rimosso altrove porta a NSInternalInconsistencyException
  • Dipendenza dall'ordine di chiamata — nei contenitori annidati, l'ordine di chiamata di viewDidDisappear per i controller figli e genitori non è garantito

Particolare attenzione va prestata alla sicurezza dei thread. Se viewDidDisappear viene chiamato sul thread principale (garantito da UIKit), ma la pulizia delle risorse coinvolge operazioni asincrone, l'accesso ai dati condivisi deve essere sincronizzato. Usare DispatchQueue.main.async all'interno di viewDidDisappear per aggiornare l'interfaccia dopo il completamento di un'attività asincrona è un approccio comune ma corretto.

Un altro anti-pattern importante — chiamare metodi delegati all'interno di viewDidDisappear che possono avviare una nuova transizione o presentazione modale. Ciò crea un ciclo in cui viewDidDisappear può essere chiamato di nuovo prima che la prima chiamata sia completata. Apple raccomanda di evitare presentazioni modali all'interno dei metodi del ciclo di vita, spostandole in gestori di eventi separati.

Domande frequenti

In cosa viewDidDisappear differisce da viewWillDisappear?

viewWillDisappear viene chiamato prima dell'inizio dell'animazione di mascheramento, quando la vista è ancora visibile. viewDidDisappear viene chiamato dopo la completa scomparsa della vista. Utilizzare viewWillDisappear per salvare i dati e viewDidDisappear per liberare le risorse.

È necessario chiamare super.viewDidDisappear?

Sì, chiamare super.viewDidDisappear(animated) è obbligatorio. UIKit utilizza questo metodo per notifiche interne e completamento dello stato di transizione. Senza la chiamata a super, UINavigationController e UITabBarController possono funzionare male.

Può viewDidDisappear non essere chiamato?

Sì, con il dismiss interattivo in iOS 13+ (scorrimento verso il basso), il metodo potrebbe non essere chiamato se il gesto non viene completato. Per garantire la ricezione dell'evento, utilizzare il delegato UIAdaptivePresentationControllerDelegate e il metodo presentationControllerDidDismiss.

Cosa è meglio: viewDidDisappear o deinit?

deinit viene chiamato solo quando l'oggetto viene distrutto, mentre viewDidDisappear viene chiamato ad ogni mascheramento. Per liberare risorse ad ogni transizione (ad esempio, disiscriversi dalle notifiche), utilizzare viewDidDisappear. Per la pulizia finale quando il controller viene rimosso, utilizzare deinit.

Come funziona viewDidDisappear in SwiftUI?

In SwiftUI, invece di viewDidDisappear, viene utilizzato il modificatore .onDisappear { }. Viene chiamato quando la vista scompare dalla gerarchia. A differenza di UIKit, SwiftUI non garantisce che onDisappear venga chiamato in tutti gli scenari di animazione.

Riepilogo

  • viewDidDisappear — l'ultimo metodo del ciclo di vita prima del mascheramento, chiamato dopo il completamento dell'animazione di transizione
  • Scopo principale — liberare risorse, fermare timer e disiscriversi dalle notifiche
  • La chiamata a super.viewDidDisappear è obbligatoria per il corretto funzionamento di UIKit
  • Si differenzia da viewWillDisappear nel momento della chiamata: dopo l'animazione, non prima
  • Non sostituisce deinit — deinit viene chiamato quando l'oggetto viene distrutto, viewDidDisappear ad ogni mascheramento
  • Non utilizzato per operazioni sincrone pesanti — bloccano il thread principale e disturbano l'animazione
  • In iOS 13+, è necessaria una gestione aggiuntiva tramite UIAdaptivePresentationControllerDelegate per una chiamata garantita

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