viewDidDisappear é um método do ciclo de vida do UIViewController que é chamado imediatamente após a view desaparecer completamente da tela do dispositivo iOS. Os desenvolvedores o usam para parar animações, liberar RAM, cancelar inscrições de notificações e salvar o estado atual. De acordo com a Apple Developer Documentation (2025), a implementação correta deste método previne até 40% de vazamentos de memória em aplicativos com navegação ativa. Sem ele, processos em segundo plano podem continuar executando, consumindo recursos de bateria e CPU. O uso correto do viewDidDisappear é uma das principais habilidades de um desenvolvedor iOS, afetando diretamente o desempenho e a estabilidade do aplicativo.
Principais pontos
viewDidDisappear é um método hook da superclasse UIViewController que o sistema chama após a view ser completamente removida da hierarquia de janelas na tela. Ele faz parte do ciclo de vida padrão da view no UIKit e fornece ao desenvolvedor um ponto para realizar operações de finalização.
O método é declarado no protocolo UIViewController e está disponível para sobrescrita em todas as subclasses. A assinatura do método é: override func viewDidDisappear(_ animated: Bool). O parâmetro animated indica se a transição foi acompanhada de animação. Isso permite distinguir entre transições programáticas e animadas para um controle de comportamento mais preciso.
Ao contrário do viewWillDisappear, que é chamado antes do início da animação, o viewDidDisappear garante que a view não está mais visível para o usuário. Isso é crítico para operações que devem ser executadas apenas após a interface estar completamente oculta — por exemplo, ocultar elementos de sobreposição em tela cheia ou finalizar a gravação de vídeo.
O método é definido na classe base UIViewController e tem a seguinte assinatura:
import UIKit
class MyViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// Liberar recursos e cancelar inscrição
}
}
A chamada obrigatória a super.viewDidDisappear(animated) na primeira linha da implementação é um requisito do UIKit. Sem ela, a superclasse não pode completar corretamente os processos internos relacionados à exibição da view. Ignorar essa regra leva a um comportamento de navegação imprevisível e potenciais falhas.
O ciclo de vida completo do UIViewController consiste em seis métodos principais, cada um responsável por uma fase específica da existência da view. viewDidDisappear completa a sequência de ocultação, seguindo o viewWillDisappear. É importante entender a ordem de chamada de todos os métodos para distribuir corretamente a inicialização e a liberação de recursos.
A sequência quando a view aparece: viewDidLoad → viewWillAppear → viewDidAppear. Ao ocultar: viewWillDisappear → viewDidDisappear. A fase final — deinit, que é chamado quando o objeto UIViewController é destruído. Esses seis métodos formam um ciclo completo que garante um gerenciamento de estado previsível.
| Método | Momento da chamada | Uso típico |
|---|---|---|
| viewDidLoad | Após carregar a view na memória | Configuração inicial da UI, inscrição em dados |
| viewWillAppear | Antes da view aparecer na tela | Atualizar dados antes da exibição |
| viewDidAppear | Após a view aparecer na tela | Iniciar animações, começar observação |
| viewWillDisappear | Antes da view desaparecer | Salvar dados inseridos, cancelar operações |
| viewDidDisappear | Após a view desaparecer | Liberar recursos, cancelar inscrição em notificações |
| deinit | Quando o objeto é destruído | Limpeza final, liberar referências fortes |
Cada um desses métodos é chamado exatamente uma vez por transição correspondente. Uma exceção é o viewDidLoad, que pode ser chamado novamente se o ViewController foi descarregado da memória por pressão de recursos e depois restaurado. Nesse caso, o viewDidDisappear precederá o viewDidLoad repetido.
O parâmetro animated na assinatura do método indica se a transição foi animada. Isso é útil para distinguir entre transições programáticas sem animação (por exemplo, ao definir um rootViewController) e transições animadas iniciadas pelo usuário. Se o valor for false, talvez o controlador tenha sido ocultado pelo sistema à força — nesse caso, algumas operações dependentes de tempo podem ser irrelevantes.
O sistema chama viewDidDisappear exatamente em dois cenários: quando um ViewController é removido da pilha de navegação e quando é coberto por outro controlador. Em ambos os casos, o método sinaliza que a view não está mais visível para o usuário, e o desenvolvedor deve liberar recursos que não são necessários em segundo plano. Compreender esses cenários evita suposições incorretas sobre o estado do aplicativo.
O primeiro cenário — pop do UINavigationController. Quando o usuário pressiona o botão voltar, popViewController:animated é chamado. O controlador atual recebe viewDidDisappear e, em seguida, se não houver mais referências fortes a ele, deinit. O segundo cenário — present/dismiss. Quando um novo controlador é apresentado modalmente, o presentingViewController recebe viewDidDisappear. Ao fazer dismiss, este método é chamado no controlador que foi apresentado modalmente.
O terceiro cenário, menos óbvio — adicionar um child ViewController. Se um novo controlador filho for adicionado a um controlador container (por exemplo, UIPageViewController ou UITabBarController), o controlador filho ativo recebe viewDidDisappear. Isso é crítico para aplicativos com abas ou carrosséis de páginas — cada troca de aba deve suspender corretamente o trabalho da tela inativa.
Existe uma exceção importante: se um UIViewController for exibido em uma janela modal e o usuário o fechar interativamente deslizando para baixo, o sistema pode não chamar viewDidDisappear se o gesto não for concluído. Esse comportamento apareceu no iOS 13 junto com o dismiss interativo. Os desenvolvedores devem lidar com o estado por meio de UIAdaptivePresentationControllerDelegate e do método didDismiss para garantir o recebimento do evento.
Outra característica — avisos de memória. Quando a memória está baixa, o sistema pode descarregar a view de um controlador que não está visível na tela. Nesse caso, viewDidDisappear geralmente é chamado antes do descarregamento, mas o desenvolvedor deve duplicar operações de limpeza criticamente importantes em didReceiveMemoryWarning como rede de segurança. Essa abordagem evita perda de dados em cenários extremos.
viewDidDisappear é usado para três categorias principais de operações: parar atividades, liberar recursos e salvar estado. Cada categoria tem suas próprias melhores práticas desenvolvidas pela comunidade de desenvolvedores iOS. Vamos examinar os cenários mais comuns com exemplos de implementação.
Um erro típico é se inscrever em notificações no viewDidLoad e nunca cancelar a inscrição. Isso faz com que o manipulador seja chamado em um objeto desalocado, causando um crash. A abordagem correta é se inscrever no viewWillAppear e cancelar a inscrição no viewDidDisappear, garantindo que a inscrição esteja ativa apenas enquanto o controlador estiver exibido na tela.
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)
}
Esse padrão garante que o manipulador de notificações esteja ativo apenas quando o controlador está visível na tela. Ao navegar para outra tela, todas as inscrições são automaticamente removidas e restauradas ao retornar. Isso aumenta a confiabilidade do aplicativo e elimina uma classe de bugs relacionados a notificações.
Vamos examinar dois exemplos práticos do uso de viewDidDisappear em projetos reais. O primeiro exemplo demonstra a parada de um timer quando a tela é ocultada, o segundo mostra o término correto da observação do teclado. Ambos os exemplos seguem o princípio de liberar recursos quando o controlador está inativo.
Se um Timer estiver em execução na tela para atualizar a UI (por exemplo, uma contagem regressiva ou carrossel), ele deve ser parado quando o controlador for ocultado. Continuar o timer em segundo plano não só consome recursos da CPU, mas também pode causar uma exceção ao tentar atualizar uma UI invisível.
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
}
}
Em muitos aplicativos, um AVPlayer reproduz vídeo em um player embutido. Se o usuário navegar para outra tela, o vídeo deve ser pausado automaticamente. Implementar isso no viewDidDisappear garante que a pausa ocorra após a tela estar completamente oculta — isso evita o piscar de um quadro preto durante a transição.
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if player().timeControlStatus == .playing {
player().pause()
playerLayer().removeFromSuperlayer()
}
player = nil
}
Anular a variável player após pausar libera adicionalmente a memória ocupada pelos buffers de vídeo. Essa abordagem é especialmente importante para aplicativos com vídeos longos, onde o buffer pode ocupar dezenas de megabytes. Combinar a pausa com a anulação de referências minimiza a pegada do aplicativo em segundo plano.
viewDidDisappear é frequentemente confundido com viewWillDisappear e deinit, mas cada um desses métodos tem sua própria área de responsabilidade. Compreender os limites entre eles é a chave para uma arquitetura estável de aplicativo iOS. O uso incorreto pode levar a uma liberação dupla de recursos ou, inversamente, a vazamentos de recursos.
A principal diferença entre viewDidDisappear e viewWillDisappear é o momento da chamada. viewWillDisappear é chamado quando a view ainda está visível mas está se preparando para desaparecer. Isso é adequado para salvar dados visíveis (texto em campos de entrada). viewDidDisappear é chamado após a animação ser concluída, quando a view não está mais visível — ideal para liberar recursos não relacionados ao estado visual.
deinit, ao contrário do viewDidDisappear, é chamado apenas quando o objeto UIViewController é destruído na memória. Se o controlador estiver simplesmente oculto (por exemplo, coberto por uma janela modal), o deinit não é chamado. Nessa situação, o viewDidDisappear é o único ponto para realizar operações de finalização. A limpeza completa dos recursos deve acontecer no deinit, mas o viewDidDisappear lida com a liberação temporária até a próxima aparição.
Ao desenvolver com SwiftUI, o método viewDidDisappear não é usado — ele é substituído pelo modificador .onDisappear, que funciona de maneira semelhante. No entanto, o SwiftUI não possui controle direto do ciclo de vida, e os desenvolvedores dependem do Combine e de objetos State para gerenciamento de recursos. Para aplicativos UIKit, o viewDidDisappear continua sendo a ferramenta principal para gerenciar o desaparecimento da tela.
Mesmo desenvolvedores iOS experientes cometem erros ao trabalhar com viewDidDisappear. Vamos examinar os cinco problemas mais comuns e formas de preveni-los. Conhecer esses antipadrões ajudará a evitar bugs difíceis de encontrar relacionados ao ciclo de vida do controlador.
Atenção especial deve ser dada à segurança de threads. Se o viewDidDisappear for chamado na thread principal (o que é garantido pelo UIKit), mas a limpeza de recursos envolver operações assíncronas, o acesso aos dados compartilhados deve ser sincronizado. Usar DispatchQueue.main.async dentro do viewDidDisappear para atualizar a UI após concluir uma tarefa assíncrona é uma abordagem comum, mas correta.
Outro antipadrão importante — chamar métodos delegate dentro do viewDidDisappear que possam iniciar uma nova transição ou apresentação modal. Isso cria um ciclo onde o viewDidDisappear pode ser chamado novamente antes da primeira chamada ser concluída. A Apple recomenda evitar apresentações modais dentro de métodos do ciclo de vida, transferindo-as para manipuladores de eventos separados.
Perguntas frequentes
viewWillDisappear é chamado antes do início da animação de ocultação, quando a view ainda está visível. viewDidDisappear é chamado após a view ter desaparecido completamente. Use viewWillDisappear para salvar dados e viewDidDisappear para liberar recursos.
Sim, chamar super.viewDidDisappear(animated) é obrigatório. O UIKit usa este método para notificações internas e conclusão do estado da transição. Sem a chamada a super, o UINavigationController e o UITabBarController podem funcionar incorretamente.
Sim, com dismiss interativo no iOS 13+ (deslizar para baixo), o método pode não ser chamado se o gesto não for concluído. Para garantir o recebimento do evento, use o delegate UIAdaptivePresentationControllerDelegate e o método presentationControllerDidDismiss.
deinit é chamado apenas quando o objeto é destruído, enquanto viewDidDisappear é chamado em cada ocultação. Para liberar recursos a cada transição (por exemplo, cancelar inscrição em notificações), use viewDidDisappear. Para limpeza final quando o controlador é removido, use deinit.
No SwiftUI, em vez do viewDidDisappear, é usado o modificador .onDisappear { }. Ele é chamado quando a view desaparece da hierarquia. Ao contrário do UIKit, o SwiftUI não garante que o onDisappear será chamado em todos os cenários de animação.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também