.onDisappear é um modificador do SwiftUI que executa um closure quando uma View é removida da hierarquia da interface. A chamada ocorre ao fechar uma tela, alternar de aba, dispensar uma janela modal ou rolar um elemento para fora da visibilidade. De acordo com a Documentação para Desenvolvedores da Apple (2026), onDisappear não garante chamada em cenários de falha ou quando o aplicativo é encerrado pelo watchdog do sistema. Saiba mais sobre SwiftUI no artigo sobre SwiftUI.
Principais pontos
.onDisappear é um modificador de View no SwiftUI que aceita um closure Void e o executa quando a View é removida da hierarquia. Junto com .onAppear, forma o ciclo de vida completo de uma tela: aparecimento — trabalho — desaparecimento. A Apple introduziu onDisappear junto com SwiftUI no iOS 13 como um análogo ao viewDidDisappear do UIKit.
Sintaticamente, .onDisappear é idêntico ao onAppear: modifica qualquer View e anexa um closure que o renderizador do SwiftUI chama quando a view é removida. Ao contrário do UIKit, onde viewDidDisappear só é acionado após a animação de transição ser concluída, onDisappear no SwiftUI pode ser chamado antes da animação terminar — no momento em que a View é marcada para remoção.
Sintaxe básica do onDisappear é tão concisa quanto a do onAppear. O modificador não aceita parâmetros adicionais — apenas o closure, que executa sincronamente na thread principal.
struct DetailView: View {
var body: some View {
Text("Detail Screen")
.onDisappear {
print("DetailView desapareceu da tela")
}
}
}
Mecanismo de chamada do onDisappear é o oposto do onAppear: elementos filhos recebem onDisappear primeiro, depois o pai. Esta regra child-first garante que os recursos filhos sejam liberados antes dos recursos do pai. Se um elemento filho depende de dados do pai, ele deve ser capaz de terminar corretamente sem o contexto do pai.
SwiftUI chama onDisappear quando a View é removida do grafo de renderização. Os gatilhos incluem: pop do NavigationStack, alternância de TabView, dispensa de modal (sheet/fullScreenCover) ou uma View renderizada condicionalmente (if/switch). Em List e ScrollView, onDisappear é chamado quando uma célula rola para fora do buffer de pré-carregamento.
Ordem child-first significa que se um VStack tem três View filhas, onDisappear é chamado primeiro para cada filho em ordem inversa, depois para o pai. Isso é crítico para limpeza adequada: temporizadores filhos são cancelados antes que o ViewModel pai libere recursos compartilhados.
struct ParentView: View {
var body: some View {
VStack {
ChildView(id: "A")
ChildView(id: "B")
}
.onDisappear {
print("Parent onDisappear — último")
}
}
}
struct ChildView: View {
let id: String
var body: some View {
Text("Child \(id)")
.onDisappear {
print("Child \(id) onDisappear")
}
}
}
Saída do console: Child B onDisappear, Child A onDisappear, Parent onDisappear — último. A ordem inversa comparada ao onAppear garante uma cadeia de limpeza correta.
Cenários de chamada do onDisappear dependem do tipo de contêiner. No NavigationStack, onDisappear é acionado ao fazer pop-to-root, pop-back normal ou dispensa de tela por deslize (interactivePopGestureRecognizer). No TabView, alternar abas chama onDisappear para a aba oculta e onAppear para a mostrada — ambos modificadores são acionados quase simultaneamente.
Em Sheet e fullScreenCover, onDisappear é chamado na dispensa programática (via @Environment(\.dismiss)) ou gesto de deslize para baixo. Um detalhe importante: se um sheet foi aberto mas o usuário trocou de aplicativo, onDisappear NÃO é chamado até o fechamento real.
| Cenário | onDisappear é chamado | Nota |
|---|---|---|
| Pop no NavigationStack | Sim | Imediatamente após a animação |
| Alternância de aba TabView | Sim | Aba atual |
| Dispensa de sheet | Sim | Antes da animação completar |
| Rolagem em List | Sim | Célula saiu da zona de pré-carregamento |
| Minimizar aplicativo | Não | Sem garantia de chamada |
| Falha/watchdog kill | Não | Não é chamado |
Principais casos de uso do onDisappear são limpeza de recursos, salvamento de estado e rastreamento. Ao contrário do onAppear, as tarefas do onDisappear executam na saída e não precisam de verificação de duplicação já que a View desaparece uma única vez.
Salvar estado no onDisappear é especialmente útil para formulários onde os dados devem ser salvos ao sair da tela. Temporizadores e assinaturas Combine são cancelados no onDisappear para evitar vazamentos ao retornar à tela.
struct FormView: View {
@State private var draftText = ""
@State private var timer: Timer?
var body: some View {
TextField("Enter text", text: $draftText)
.onAppear {
timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
saveDraft()
}
}
.onDisappear {
timer?.invalidate()
timer = nil
saveDraft()
}
}
private func saveDraft() {
UserDefaults.standard.set(draftText, forKey: "draft")
}
}
Cancelamento do temporizador no onDisappear impede a execução de código após a tela já estar fechada. Sem cancelamento, o temporizador pode tentar atualizar @State que não pertence mais à View atual, causando um aviso em tempo de execução.
Tempo de permanência na tela é um cenário clássico de rastreamento. Registre o tempo no onAppear, calcule a diferença no onDisappear e envie um evento analítico com a duração da sessão.
struct TrackedView: View {
@State private var appearTime: Date?
var body: some View {
Text("Tracked Screen")
.onAppear {
appearTime = Date()
Analytics.shared.logEvent("screen_view", params: ["screen": "TrackedView"])
}
.onDisappear {
if let start = appearTime {
let duration = Date().timeIntervalSince(start)
Analytics.shared.logEvent("screen_close", params: [
"screen": "TrackedView",
"duration_ms": Int(duration * 1000)
])
}
}
}
}
A diferença chave entre onDisappear e onAppear é a ordem de chamada e as garantias de execução. onAppear é chamado quando uma View é adicionada à hierarquia e pode ser chamado novamente na recriação. onDisappear é chamado na remoção e só é garantido de acionar em fechamento normal, não em cenários de falha.
De acordo com a WWDC 2024, a Apple recomenda tratar onDisappear como um ponto de limpeza, não como um ponto de confirmação de dados. Dados criticamente importantes (pagamentos, registros) devem ser salvos em tempo real, não no momento em que a View desaparece, já que onDisappear não é garantido quando o aplicativo é minimizado.
| Característica | .onAppear | .onDisappear |
|---|---|---|
| Momento da chamada | View adicionada à hierarquia | View removida da hierarquia |
| Ordem | Parent-first | Child-first |
| Garantia | Alta | Não em falhas |
| Tarefa principal | Inicialização | Limpeza |
| Chamada repetida | Na recriação da View | Uma vez por desaparecimento |
Recomendação: use onDisappear apenas para limpeza não crítica e rastreamento. Para persistência de dados, use scenePhase ou notificações applicationWillTerminate no AppDelegate.
Cenário 1: reprodução estilo YouTube. Na tela de detalhes do vídeo, onDisappear salva a posição de reprodução no UserDefaults. Ao reabrir, onAppear restaura a posição do UserDefaults, criando uma experiência de visualização contínua.
Cenário 2: cancelar assinatura Combine. Se um ViewModel usa publicadores Combine, onDisappear cancela a assinatura via cancellable?.cancel(). Isso impede atualizações da UI após sair da tela, o que é especialmente importante para listas com paginação e consultas de busca.
Cenário 3: fechar WebSocket. Em aplicativos com conexões em tempo real (mensageiros, feeds de cotações), onDisappear fecha a conexão WebSocket para economizar bateria e dados. A reconexão ocorre no onAppear ao retornar à tela.
WebSocket é um recurso típico que precisa ser fechado ao sair da tela. No exemplo abaixo, onDisappear desconecta o socket e onAppear o reconecta, proporcionando economia significativa de dados para aplicativos com várias telas.
struct ChatView: View {
@StateObject private var socket = WebSocketManager()
var body: some View {
ChatListView(messages: socket.messages)
.onAppear {
socket.connect()
}
.onDisappear {
socket.disconnect()
}
}
}
Importante: ao alternar entre abas do TabView, onDisappear da aba atual e onAppear da próxima aba são acionados quase simultaneamente. Para WebSocket isso pode causar um ciclo de desconexão-reconexão que cria carga desnecessária. A solução é usar um atraso ou verificar se o socket é necessário na próxima tela.
Perguntas frequentes
Sim, .onDisappear não garante chamada em caso de falha do aplicativo (crash, watchdog kill), minimização do aplicativo sem fechar a tela ou cenários do sistema onde o aplicativo é encerrado em segundo plano. Para dados críticos, use scenePhase ou applicationWillTerminate.
.onDisappear é acionado quando uma View é removida da hierarquia — um callback local para uma tela específica. .scenePhase (via @Environment(\.scenePhase)) é acionado quando o estado de todo o aplicativo muda: active, inactive, background. Use onAppear+onDisappear para rastreamento de tempo na tela e scenePhase para persistência de estado global.
A causa é a alternância rápida de abas ou push/pop repetido da mesma tela. O SwiftUI pode criar uma nova instância de View, remover a antiga, criar novamente — cada vez chamando onDisappear e onAppear. Verifique se você está usando .id(), .equatable() ou recriando a View no body do pai.
Sim, .onDisappear é totalmente suportado no macOS (10.15+) com o mesmo comportamento: é chamado ao fechar janela, remover painel de split view ou dispensar modal. No macOS, onDisappear também é chamado ao ocultar a janela (não apenas ao fechá-la), o que é importante considerar para aplicativos macOS.
Salve uma referência à URLSessionTask em @State e chame task.cancel() no onDisappear. Alternativamente, use o modificador .task, que cancela automaticamente a operação assíncrona quando a View desaparece. .task é preferível para todas as operações assíncronas, incluindo URLSession.
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