viewDidDisappear: същност на метода, жизнен цикъл на UIViewController и кога се извиква

Автор: IT Sectr Публикувано: 2026-03-05 Време за четене: 9 мин

viewDidDisappear — е метод на жизнения цикъл на UIViewController, който се извиква веднага след пълното изчезване на изгледа (view) от екрана на iOS устройство. Разработчиците го използват за спиране на анимации, освобождаване на RAM памет, отписване от известия и запазване на текущото състояние. Според Apple Developer Documentation (2025), правилната имплементация на този метод предотвратява до 40% от изтичанията на памет в приложения с активна навигация. Без него фоновите процеси могат да продължат работа, изразходвайки ресурси на батерията и процесора. Правилното използване на viewDidDisappear е едно от ключовите умения на iOS разработчика, което пряко влияе върху производителността и стабилността на приложението.

Основни точки

  • viewDidDisappear — финален метод на жизнения цикъл, извиква се след изчезване на view от екрана
  • Използва се за освобождаване на ресурси: спиране на таймери, скриване на индикатори за зареждане
  • Задължителен за отписване от NotificationCenter и KVO наблюдения за избягване на изтичания
  • Различава се от viewWillDisappear по това, че се извиква след завършване на анимацията на прехода
  • Не замества deinit — deinit отговаря за крайното унищожаване на обекта

Какво е viewDidDisappear?

viewDidDisappear — е метод-кука на суперкласа UIViewController, който системата извиква, след като изгледът (view) бъде напълно премахнат от йерархията на прозорците на екрана. Той е част от стандартния жизнен цикъл на изглед в UIKit и предоставя на разработчика точка за изпълнение на завършващи операции.

Методът е деклариран в протокола UIViewController и е достъпен за замяна във всички подкласове. Сигнатурата на метода: override func viewDidDisappear(_ animated: Bool). Параметърът animated указва дали преходът е бил придружен от анимация. Това позволява разграничаване на програмни и анимирани преходи за по-прецизен контрол на поведението.

За разлика от viewWillDisappear, който се извиква преди започване на анимацията, viewDidDisappear гарантира, че изгледът вече не е видим за потребителя. Това е критично за операции, които трябва да се изпълнят само след пълно скриване на интерфейса — например скриване на целоекранни overlay елементи или завършване на запис на видео.

Сигнатура и декларация

Методът е дефиниран в базовия клас UIViewController и има следната сигнатура:

swift
import UIKit

class MyViewController: UIViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // Освобождаване на ресурси и отписване
    }
}

Задължителното извикване на super.viewDidDisappear(animated) в първия ред на имплементацията — това е изискване на UIKit. Без него суперкласът не може да завърши правилно вътрешните процеси, свързани с показването на изгледа. Игнорирането на това правило води до непредвидимо поведение на навигацията и потенциални сривове.

Място на viewDidDisappear в жизнения цикъл на UIViewController

Пълният жизнен цикъл на UIViewController се състои от шест ключови метода, всеки от които отговаря за определена фаза на съществуване на изгледа. viewDidDisappear завършва последователността на скриване, следвайки viewWillDisappear. Важно е да се разбере редът на извикване на всички методи, за да се разпредели правилно инициализацията и освобождаването на ресурси.

Редът при появяване на изгледа: viewDidLoadviewWillAppearviewDidAppear. При скриване: viewWillDisappearviewDidDisappear. Крайната фаза — deinit, който се извиква при унищожаване на обекта UIViewController. Тези шест метода формират пълен цикъл, гарантиращ предвидимо управление на състоянието.

МетодМомент на извикванеТипично приложение
viewDidLoadСлед зареждане на изгледа в паметтаНачална настройка на UI, абонамент за данни
viewWillAppearПреди появяване на изгледа на екранаАктуализиране на данни преди показване
viewDidAppearСлед появяване на изгледа на екранаСтартиране на анимации, начало на анимация
viewWillDisappearПреди изчезване на изгледаЗапазване на въведени данни, отмяна на операции
viewDidDisappearСлед изчезване на изгледаОсвобождаване на ресурси, отписване от известия
deinitПри унищожаване на обектаКрайно почистване, освобождаване на силни референции

Всеки от тези методи се извиква точно веднъж за съответния преход. Изключение — viewDidLoad, който може да бъде извикан отново, ако ViewController бъде изтоварен от паметта поради липса на ресурси и след това възстановен. В такъв случай viewDidDisappear ще предшества новото viewDidLoad.

Връзка с анимацията на прехода

Параметърът animated в сигнатурата на метода указва дали преходът е бил анимиран. Това е полезно за разграничаване на програмни преходи без анимация (например при задаване на rootViewController) и анимирани преходи, инициирани от потребителя. Ако стойността е false, възможно е контролерът да е бил принудително скрит от системата — в този случай някои зависими от времето операции може да са неактуални.

Кога се извиква viewDidDisappear

Системата извиква viewDidDisappear точно в два сценария: когато ViewController се премахва от стека за навигация и когато се покрива от друг контролер. И в двата случая методът сигнализира, че изгледът вече не е видим за потребителя и разработчикът трябва да освободи ресурси, които не са необходими на фона. Разбирането на тези сценарии предотвратява грешни предположения за състоянието на приложението.

Първи сценарий — pop от UINavigationController. Когато потребителят натисне бутона „Назад”, се извиква popViewController: animated. Текущият контролер получава viewDidDisappear, а след това, ако няма повече силни референции към него, deinit. Втори сценарий — present/dismiss. При модално показване на нов контролер presentingViewController получава viewDidDisappear. При dismiss този метод се извиква при контролера, който е бил показан модално.

Трети, по-малко очевиден сценарий — добавяне на child ViewController. Ако към контейнерен контролер (например UIPageViewController или UITabBarController) се добави нов дъщерен контролер, активният дъщерен контролер получава viewDidDisappear. Това е критично за приложения с раздели или карусел от страници — всяка смяна на раздел трябва правилно да спира работата на неактивния екран.

Изключения и неочевидни случаи

Съществува важно изключение: ако UIViewController се показва в модален прозорец и потребителят го затвори интерактивно чрез плъзгане надолу, системата може да не извика viewDidDisappear при непълно плъзгане. Това поведение се появи в iOS 13 заедно с интерактивния dismiss. Разработчиците трябва да управляват състоянието чрез UIAdaptivePresentationControllerDelegate и метода didDismiss за гарантирано получаване на събитието.

Друга особеност — предупреждения за памет. При недостиг на памет системата може да изтовари изгледа на контролер, който не се показва на екрана. В този случай viewDidDisappear обикновено се извиква преди изтоварването, но разработчикът трябва да дублира критично важните операции за освобождаване в didReceiveMemoryWarning за сигурност. Такъв подход предотвратява загуба на данни в екстремни сценарии.

Типични сценарии за използване

viewDidDisappear се използва за три основни категории операции: спиране на активности, освобождаване на ресурси и запазване на състояние. Всяка категория има своите най-добри практики, разработени от общността на iOS разработчиците. Нека разгледаме най-честите сценарии с примери за имплементация.

  • Спиране на анимации — извикване на layer.removeAllAnimations() за CALayer, спиране на UIView.animate блокове
  • Освобождаване на ресурси — зануляване на големи изображения, нулиране на кеширани данни, затваряне на файлови дескриптори
  • Отписване от известия — премахване на наблюдатели от NotificationCenter.default, спиране на KVO наблюдения
  • Запазване на напредъка — запис на чернови в CoreData или UserDefaults при затваряне на екрана за редактиране
  • Скриване на overlay — премахване на индикатори за зареждане, подсказки и popover елементи, които не трябва да останат след прехода

Пример: отписване от NotificationCenter

Типична грешка — абониране за известия в viewDidLoad и никога не се отписване. Това води до извикване на handler на унищожен обект, което причинява срив. Правилният подход — абониране в viewWillAppear и отписване в viewDidDisappear, което гарантира, че абонаментът е активен само докато контролерът се показва на екрана.

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)
}

Този модел гарантира, че handler на известия е активен само когато контролерът е видим на екрана. При преминаване към друг екран всички абонаменти автоматично се премахват, а при връщане се възстановяват. Това повишава надеждността на приложението и елиминира клас грешки, свързани с известия.

Примери за код в Swift

Нека разгледаме два практически примера за използване на viewDidDisappear в реални проекти. Първият пример демонстрира спиране на таймер при скриване на екрана, вторият — правилно завършване на наблюдение на клавиатурата. И двата примера следват принципа на освобождаване на ресурси при неактивност на контролера.

Спиране на таймер

Ако на екрана работи Timer за актуализиране на UI (например обратно броене или карусел), той трябва да бъде спрян при скриване на контролера. Продължаването на работата на таймера на фона не само изразходва ресурси на процесора, но може също да причини изключение при опит за актуализиране на невидим UI.

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
    }
}

Паузиране на видео при скриване

В много приложения AVPlayer възпроизвежда видео във вграден плейър. Ако потребителят премине към друг екран, видеото трябва автоматично да се паузира. Имплементацията в viewDidDisappear гарантира, че паузата настъпва след пълно скриване на екрана — това предотвратява мигане на черен кадър при прехода.

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

Зануляването на променливата player след пауза допълнително освобождава паметта, заета от видео буферите. Този подход е особено важен за приложения с дълги видеа, където буферът може да заема десетки мегабайта. Комбинирането на пауза със зануляване на референции минимизира отпечатъка на приложението на фона.

viewDidDisappear и други методи на жизнения цикъл

viewDidDisappear често се бърка с viewWillDisappear и deinit, но всеки от тези методи има своя зона на отговорност. Разбирането на границите между тях е ключът към стабилна архитектура на iOS приложение. Неправилното използване може да доведе до двойно освобождаване на ресурси или, обратно, до тяхното изтичане.

Основната разлика на viewDidDisappear от viewWillDisappear — моментът на извикване. viewWillDisappear се извиква, когато изгледът е все още видим, но вече се подготвя за изчезване. Това е подходящо за запазване на видими данни (текст в полета за въвеждане). viewDidDisappear се извиква след завършване на анимацията, когато изгледът е гарантирано невидим — идеално за освобождаване на ресурси, несвързани с визуалното състояние.

deinit, за разлика от viewDidDisappear, се извиква само при унищожаване на обекта UIViewController в паметта. Ако контролерът е просто скрит (например покрит от модален прозорец), deinit не се извиква. В тази ситуация viewDidDisappear е единствената точка за изпълнение на завършващи операции. Пълното освобождаване на ресурси трябва да се случи в deinit, но viewDidDisappear отговаря за временно освобождаване до повторното появяване.

Кога да използвате кой метод

  • viewWillDisappear — запазване на въведени данни, изпращане на аналитика за начало на прехода
  • viewDidDisappear — спиране на анимации, отписване от известия, скриване на overlay елементи
  • deinit — крайно освобождаване на големи ресурси, затваряне на мрежови връзки

При разработка с SwiftUI методът viewDidDisappear не се прилага — заменя се от модификатора .onDisappear, който работи по подобен начин. В SwiftUI обаче липсва пряк контрол над жизнения цикъл и разработчиците разчитат на Combine и State обекти за управление на ресурси. За UIKit приложения viewDidDisappear остава основният инструмент за управление на скриване на екрана.

Типични грешки при имплементация

Дори опитни iOS разработчици допускат грешки в работата с viewDidDisappear. Нека разгледаме петте най-чести проблема и начини за предотвратяването им. Познаването на тези анти-модели помага да се избегнат трудно откриваеми грешки, свързани с жизнения цикъл на контролерите.

  • Пропускане на super.viewDidDisappear — извикването на super е задължително за правилната работа на UIKit, липсата му може да причини нарушаване на вътрешното състояние на контролера
  • Тежки операции в viewDidDisappear — синхронен запис на големи данни в viewDidDisappear блокира основната нишка и влошава анимацията на прехода
  • Забравено отписване от известия — ако removeObserver не се извика в viewDidDisappear, handler може да се активира върху zombie обект, причинявайки EXC_BAD_ACCESS
  • Двойно отписване — премахване на наблюдател, който вече е премахнат на друго място, води до изключение NSInternalInconsistencyException
  • Зависимост от реда на извикване — във вложени контейнери редът на извикване на viewDidDisappear при дъщерни и родителски контролери не е гарантиран

Особено внимание изисква нишковата безопасност. Ако viewDidDisappear се извиква на основната нишка (което UIKit гарантира), но освобождаването на ресурси включва асинхронни операции, трябва да се синхронизира достъпът до споделени данни. Използването на DispatchQueue.main.async вътре в viewDidDisappear за актуализиране на UI след завършване на асинхронна задача — често срещан, но правилен подход.

Друг важен анти-модел — извикване на делегатски методи вътре в viewDidDisappear, които могат да инициират нов преход или модално показване. Това създава цикъл, в който viewDidDisappear може да бъде извикан отново преди завършване на първото извикване. Apple препоръчва да се избягват модални показвания вътре в методите на жизнения цикъл, като се изнасят в отделни обработчици на събития.

Често задавани въпроси

По какво се различава viewDidDisappear от viewWillDisappear?

viewWillDisappear се извиква преди започване на анимацията на скриване, когато изгледът е все още видим. viewDidDisappear — след пълно изчезване на изгледа. За запазване на данни използвайте viewWillDisappear, за освобождаване на ресурси — viewDidDisappear.

Трябва ли да се извиква super.viewDidDisappear?

Да, извикването на super.viewDidDisappear(animated) е задължително. UIKit използва този метод за вътрешни уведомления и завършване на състоянието на прехода. Без извикване на super са възможни сривове в UINavigationController и UITabBarController.

Може ли viewDidDisappear да не се извика?

Да, при интерактивен dismiss в iOS 13+ (плъзгане надолу) методът може да не се извика, ако жестът не е завършен. За гарантирано получаване на събитието използвайте делегата UIAdaptivePresentationControllerDelegate и метода presentationControllerDidDismiss.

Кое е по-добро: viewDidDisappear или deinit?

deinit се извиква само при унищожаване на обекта, докато viewDidDisappear се извиква при всяко скриване. За освобождаване на ресурси при всеки преход (например отписване от известия) използвайте viewDidDisappear. За крайно почистване при премахване на контролера — deinit.

Как работи viewDidDisappear в SwiftUI?

В SwiftUI вместо viewDidDisappear се използва модификаторът .onDisappear { }. Той се извиква при скриване на изгледа от йерархията. За разлика от UIKit, SwiftUI не гарантира извикване на onDisappear във всички сценарии по време на анимации.

Резюме

  • viewDidDisappear — последният метод на жизнения цикъл преди скриване, извиква се след завършване на анимацията на прехода
  • Основно предназначение — освобождаване на ресурси, спиране на таймери и отписване от известия
  • Задължително извикване на super.viewDidDisappear за правилна работа на UIKit
  • Различава се от viewWillDisappear по момента на извикване: след анимацията, а не преди нея
  • Не замества deinit — deinit се извиква при унищожаване на обекта, viewDidDisappear при всяко скриване
  • Не се използва за тежки синхронни операции — те блокират основната нишка и нарушават анимацията
  • В iOS 13+ се изисква допълнителна обработка чрез UIAdaptivePresentationControllerDelegate за гарантирано извикване

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също