viewDidDisappear — este o metodă a ciclului de viață UIViewController, care este apelată imediat după dispariția completă a vizualizării (view) de pe ecranul dispozitivului iOS. Dezvoltatorii o folosesc pentru a opri animațiile, a elibera memoria RAM, a se dezabona de la notificări și a salva starea curentă. Conform Apple Developer Documentation (2025), implementarea corectă a acestei metode previne până la 40% din scurgerile de memorie în aplicațiile cu navigare activă. Fără ea, procesele de fundal pot continua să ruleze, consumând resursele bateriei și ale procesorului. Utilizarea corectă a viewDidDisappear este una dintre abilitățile cheie ale dezvoltatorului iOS, care influențează direct performanța și stabilitatea aplicației.
Puncte principale
viewDidDisappear — este o metodă hook a superclasei UIViewController, pe care sistemul o apelează după ce vizualizarea (view) a fost complet eliminată din ierarhia ferestrelor de pe ecran. Face parte din ciclul de viață standard al vizualizării în UIKit și oferă dezvoltatorului un punct pentru executarea operațiilor de finalizare.
Metoda este declarată în protocolul UIViewController și este disponibilă pentru suprascriere în toate subclasele. Semnătura metodei: override func viewDidDisappear(_ animated: Bool). Parametrul animated indică dacă tranziția a fost însoțită de animație. Acest lucru permite diferențierea tranzițiilor programatice și animate pentru un control mai precis al comportamentului.
Spre deosebire de viewWillDisappear, care este apelată înainte de începerea animației, viewDidDisappear garantează că vizualizarea nu mai este vizibilă pentru utilizator. Acest lucru este critic pentru operațiile care trebuie executate doar după ascunderea completă a interfeței — de exemplu, ascunderea elementelor overlay pe ecran complet sau finalizarea înregistrării video.
Metoda este definită în clasa de bază UIViewController și are următoarea semnătură:
import UIKit
class MyViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// Eliberarea resurselor și dezabonarea
}
}
Apelul obligatoriu al super.viewDidDisappear(animated) în prima linie a implementării — este o cerință UIKit. Fără el, superclasa nu poate finaliza corect procesele interne legate de afișarea vizualizării. Ignorarea acestei reguli duce la un comportament imprevizibil al navigării și la potențiale defecțiuni.
Ciclul de viață complet al UIViewController constă din șase metode cheie, fiecare răspunzând de o anumită fază a existenței vizualizării. viewDidDisappear completează secvența de ascundere, urmând după viewWillDisappear. Este important să înțelegem ordinea de apelare a tuturor metodelor pentru a distribui corect inițializarea și eliberarea resurselor.
Ordinea la apariția vizualizării: viewDidLoad → viewWillAppear → viewDidAppear. La ascundere: viewWillDisappear → viewDidDisappear. Faza finală — deinit, care este apelată la distrugerea obiectului UIViewController. Aceste șase metode formează un ciclu complet, garantând o gestionare previzibilă a stării.
| Metodă | Momentul apelării | Aplicare tipică |
|---|---|---|
| viewDidLoad | După încărcarea vizualizării în memorie | Configurarea inițială UI, abonarea la date |
| viewWillAppear | Înainte de apariția vizualizării pe ecran | Actualizarea datelor înainte de afișare |
| viewDidAppear | După apariția vizualizării pe ecran | Pornirea animațiilor, începerea animației |
| viewWillDisappear | Înainte de dispariția vizualizării | Salvarea datelor introduse, anularea operațiilor |
| viewDidDisappear | După dispariția vizualizării | Eliberarea resurselor, dezabonarea de la notificări |
| deinit | La distrugerea obiectului | Curățarea finală, eliberarea referințelor puternice |
Fiecare dintre aceste metode este apelată exact o dată pentru tranziția corespunzătoare. Excepție — viewDidLoad, care poate fi apelată din nou dacă ViewController a fost descărcat din memorie din cauza lipsei de resurse și apoi restaurat. În acest caz, viewDidDisappear va preceda noul viewDidLoad.
Parametrul animated din semnătura metodei indică dacă tranziția a fost animată. Acest lucru este util pentru a diferenția tranzițiile programatice fără animație (de exemplu, la setarea rootViewController) de cele animate inițiate de utilizator. Dacă valoarea este false, este posibil ca controlerul să fi fost ascuns forțat de sistem — în acest caz, unele operații dependente de timp pot fi irelevante.
Sistemul apelează viewDidDisappear exact în două scenarii: când ViewController este eliminat din stiva de navigare și când este acoperit de un alt controler. În ambele cazuri, metoda semnalează că vizualizarea nu mai este vizibilă pentru utilizator, iar dezvoltatorul trebuie să elibereze resursele care nu sunt necesare în fundal. Înțelegerea acestor scenarii previne presupunerile greșite despre starea aplicației.
Primul scenariu — pop din UINavigationController. Când utilizatorul apasă butonul „Înapoi”, se apelează popViewController: animated. Controlerul curent primește viewDidDisappear, iar apoi, dacă nu mai există referințe puternice la el, deinit. Al doilea scenariu — present/dismiss. La afișarea modală a unui nou controler, presentingViewController primește viewDidDisappear. La dismiss, această metodă este apelată la controlerul care a fost afișat modal.
Al treilea scenariu, mai puțin evident — adăugarea unui child ViewController. Dacă la un controler container (de exemplu, UIPageViewController sau UITabBarController) se adaugă un nou controler copil, controlerul copil activ primește viewDidDisappear. Acest lucru este critic pentru aplicațiile cu file sau carusele de pagini — fiecare schimbare de filă trebuie să întrerupă corect activitatea ecranului inactiv.
Există o excepție importantă: dacă UIViewController este afișat într-o fereastră modală, iar utilizatorul îl închide interactiv printr-o glisare în jos, sistemul poate să nu apeleze viewDidDisappear la o glisare incompletă. Acest comportament a apărut în iOS 13 odată cu dismiss-ul interactiv. Dezvoltatorii trebuie să gestioneze starea prin UIAdaptivePresentationControllerDelegate și metoda didDismiss pentru a primi garantat evenimentul.
O altă caracteristică — avertismentele de memorie. La lipsa de memorie, sistemul poate descărca vizualizarea controlerului care nu este afișată pe ecran. În acest caz, viewDidDisappear este de obicei apelată înainte de descărcare, dar dezvoltatorul ar trebui să dubleze operațiile critic importante de eliberare în didReceiveMemoryWarning pentru siguranță. O astfel de abordare previne pierderea datelor în scenarii extreme.
viewDidDisappear este utilizată pentru trei categorii principale de operații: oprirea activităților, eliberarea resurselor și salvarea stării. Fiecare categorie are propriile best practices elaborate de comunitatea dezvoltatorilor iOS. Să analizăm cele mai frecvente scenarii cu exemple de implementare.
O eroare tipică — abonarea la notificări în viewDidLoad și niciodată dezabonarea. Aceasta duce la apelarea handler-ului pe un obiect distrus, ceea ce provoacă un crash. Abordarea corectă — abonarea în viewWillAppear și dezabonarea în viewDidDisappear, ceea ce garantează actualitatea abonării doar în timpul afișării controlerului pe ecran.
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)
}
Acest model garantează că handler-ul de notificări este activ doar când controlerul este vizibil pe ecran. La trecerea la un alt ecran, toate abonările sunt eliminate automat, iar la revenire, sunt restaurate. Acest lucru crește fiabilitatea aplicației și elimină clasa de erori legate de notificări.
Să analizăm două exemple practice de utilizare a viewDidDisappear în proiecte reale. Primul exemplu demonstrează oprirea unui timer la ascunderea ecranului, al doilea — încheierea corectă a observării tastaturii. Ambele exemple urmează principiul eliberării resurselor la inactivitatea controlerului.
Dacă pe ecran rulează un Timer pentru actualizarea UI (de exemplu, numărătoare inversă sau carusel), acesta trebuie oprit la ascunderea controlerului. Continuarea funcționării timer-ului în fundal nu doar consumă resursele procesorului, dar poate provoca și o excepție la încercarea de a actualiza un UI invizibil.
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
}
}
În multe aplicații, AVPlayer redă videoclipuri într-un player încorporat. Dacă utilizatorul trece la un alt ecran, videoclipul trebuie să se pună automat pe pauză. Implementarea în viewDidDisappear garantează că pauza are loc după ascunderea completă a ecranului — acest lucru previne pâlpâirea unui cadru negru la tranziție.
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if player().timeControlStatus == .playing {
player().pause()
playerLayer().removeFromSuperlayer()
}
player = nil
}
Anularea variabilei player după pauză eliberează suplimentar memoria ocupată de bufferele video. Această abordare este deosebit de importantă pentru aplicațiile cu videoclipuri lungi, unde buffer-ul poate ocupa zeci de megaocteți. Combinarea pauzei cu anularea referințelor minimizează amprenta aplicației în fundal.
viewDidDisappear este adesea confundată cu viewWillDisappear și deinit, însă fiecare dintre aceste metode are propria zonă de responsabilitate. Înțelegerea granițelor dintre ele este cheia unei arhitecturi stabile a aplicației iOS. Utilizarea incorectă poate duce la eliberarea dublă a resurselor sau, dimpotrivă, la scurgerea acestora.
Principala diferență dintre viewDidDisappear și viewWillDisappear — momentul apelării. viewWillDisappear este apelată când vizualizarea este încă vizibilă, dar se pregătește de dispariție. Acest lucru este potrivit pentru salvarea datelor vizibile (text în câmpurile de intrare). viewDidDisappear este apelată după finalizarea animației, când vizualizarea este garantat invizibilă — ideală pentru eliberarea resurselor nelegate de starea vizuală.
deinit, spre deosebire de viewDidDisappear, este apelată doar la distrugerea obiectului UIViewController în memorie. Dacă controlerul este doar ascuns (de exemplu, acoperit de o fereastră modală), deinit nu este apelat. În această situație, viewDidDisappear este singurul punct pentru executarea operațiilor de finalizare. Eliberarea completă a resurselor ar trebui să aibă loc în deinit, dar viewDidDisappear răspunde de eliberarea temporară până la reapariție.
În dezvoltarea cu SwiftUI, metoda viewDidDisappear nu se aplică — este înlocuită de modificatorul .onDisappear, care funcționează similar. Cu toate acestea, în SwiftUI nu există un control direct asupra ciclului de viață, iar dezvoltatorii se bazează pe Combine și obiecte State pentru gestionarea resurselor. Pentru aplicațiile UIKit, viewDidDisappear rămâne instrumentul principal de gestionare a ascunderii ecranului.
Chiar și dezvoltatorii iOS experimentați fac greșeli în lucrul cu viewDidDisappear. Să analizăm cinci probleme frecvente și modalități de prevenire a acestora. Cunoașterea acestor anti-patterns ajută la evitarea erorilor greu de depistat legate de ciclul de viață al controlerelor.
O atenție deosebită necesită siguranța firelor de execuție. Dacă viewDidDisappear este apelată pe firul principal (ceea ce este garantat de UIKit), dar eliberarea resurselor include operații asincrone, este necesară sincronizarea accesului la datele partajate. Utilizarea DispatchQueue.main.async în interiorul viewDidDisappear pentru actualizarea UI după finalizarea unei sarcini asincrone — este o abordare comună, dar corectă.
Un alt anti-pattern important — apelarea metodelor delegate în interiorul viewDidDisappear care pot iniția o nouă tranziție sau afișare modală. Acest lucru creează un ciclu în care viewDidDisappear poate fi apelată din nou înainte de finalizarea primei apelări. Apple recomandă evitarea afișărilor modale în interiorul metodelor ciclului de viață, mutându-le în handlere separate de evenimente.
Întrebări frecvente
viewWillDisappear este apelată înainte de începerea animației de ascundere, când view este încă vizibilă. viewDidDisappear — după dispariția completă a view. Pentru salvarea datelor folosiți viewWillDisappear, pentru eliberarea resurselor — viewDidDisappear.
Da, apelul super.viewDidDisappear(animated) este obligatoriu. UIKit folosește această metodă pentru notificări interne și finalizarea stării de tranziție. Fără apelul super, sunt posibile defecțiuni în UINavigationController și UITabBarController.
Da, la dismiss-ul interactiv în iOS 13+ (glisare în jos), metoda poate să nu fie apelată dacă gestul nu este finalizat. Pentru a primi garantat evenimentul, utilizați delegatul UIAdaptivePresentationControllerDelegate și metoda presentationControllerDidDismiss.
deinit este apelată doar la distrugerea obiectului, iar viewDidDisappear la fiecare ascundere. Pentru eliberarea resurselor la fiecare tranziție (de exemplu, dezabonarea de la notificări) folosiți viewDidDisappear. Pentru curățarea finală la eliminarea controlerului — deinit.
În SwiftUI, în loc de viewDidDisappear se utilizează modificatorul .onDisappear { }. Acesta este apelat la ascunderea vizualizării din ierarhie. Spre deosebire de UIKit, SwiftUI nu garantează apelarea onDisappear în toate scenariile în timpul animațiilor.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și