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 è 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.
Il metodo è definito nella classe base UIViewController e ha la seguente firma:
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.
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: viewDidLoad → viewWillAppear → viewDidAppear. Quando si nasconde: viewWillDisappear → viewDidDisappear. 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.
| Metodo | Momento della chiamata | Utilizzo tipico |
|---|---|---|
| viewDidLoad | Dopo il caricamento della vista in memoria | Configurazione iniziale dell'interfaccia, abbonamento ai dati |
| viewWillAppear | Prima che la vista appaia sullo schermo | Aggiornamento dei dati prima della visualizzazione |
| viewDidAppear | Dopo che la vista è apparsa sullo schermo | Avvio delle animazioni, inizio dell'osservazione |
| viewWillDisappear | Prima che la vista scompaia | Salvataggio dei dati inseriti, annullamento delle operazioni |
| viewDidDisappear | Dopo che la vista è scomparsa | Liberazione delle risorse, disiscrizione dalle notifiche |
| deinit | Quando l'oggetto viene distrutto | Pulizia 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.
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.
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.
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.
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.
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.
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.
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.
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.
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
}
}
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.
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 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 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.
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.
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
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.
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.
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.
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.
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
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