ViewController Lifecycle é a sequência de métodos que o UIKit chama automaticamente ao gerenciar telas no iOS. De acordo com a Documentação da Apple, cada UIViewController passa por um conjunto previsível de estados: desde a criação da View até sua aparição e ocultação. Compreender a ordem e a finalidade desses métodos é uma condição necessária para o funcionamento estável de um app iOS.
Pontos principais
ViewController Lifecycle é um conjunto de métodos que o UIViewController recebe do UIKit ao longo de sua existência. Cada tela em um app iOS passa sequencialmente pelos estágios de criação, carregamento da View, aparição na tela, ocultação e liberação de memória. O UIKit chama automaticamente os métodos correspondentes em cada estágio, e o desenvolvedor os sobrescreve para adicionar sua lógica.
A arquitetura do UIViewController é fundamental para o UIKit e continua relevante mesmo na era do SwiftUI — muitos projetos ainda usam a abordagem clássica ou uma arquitetura híbrida. Entender o Lifecycle permite prever quando as subviews estão disponíveis, quando é seguro modificar o layout e quais operações realizar ao aparecer ou ocultar a tela.
Cada método do ciclo de vida tem um propósito específico: alguns são chamados uma única vez durante toda a vida do controlador, outros — a cada aparição ou ocultação. Misturar a lógica entre os métodos leva a erros difíceis de encontrar: vazamentos de memória, atualizações incorretas de dados e solicitações de rede desnecessárias.
Seis métodos formam o ciclo de vida completo do UIViewController. A ordem de chamada é fixa e não depende do método de navegação — push, present ou unwind segue seguem o mesmo cronograma.
loadView é o primeiro método do ciclo, chamado quando a View do controlador ainda não existe. Se você usa Storyboard, o UIKit carrega automaticamente a View do arquivo xib. Ao criar a interface programaticamente, você sobrescreve este método atribuindo a View raiz manualmente. Na maioria dos projetos, o loadView não é tocado — o trabalho é feito no viewDidLoad.
Sobrescrever o loadView só é necessário em casos específicos: quando toda a interface é criada em código sem Storyboard, ou quando a View raiz precisa ser de uma classe não padrão. A Apple recomenda não chamar super.loadView ao sobrescrever — você assume total responsabilidade pela criação da View.
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
viewDidLoad é o método mais usado do ciclo. Ele é chamado uma vez após a View ser carregada na memória, mas ainda não exibida na tela. Aqui você configura as subviews, preenche tabelas com dados, registra células e se inscreve em notificações que duram toda a vida do controlador.
Uma característica importante: o viewDidLoad não é chamado novamente quando a tela é exibida novamente. Se você precisar atualizar dados toda vez que a tela aparecer — use viewWillAppear. Coloque apenas operações únicas no viewDidLoad que sejam necessárias para a configuração básica.
viewWillAppear é chamado toda vez imediatamente antes da View se tornar visível para o usuário. Este método recebe um parâmetro animated que indica se a aparição é animada. Aqui você atualiza dados, recarrega tabelas, configura a NavigationBar e oculta ou exibe elementos dependendo do estado da aplicação.
Use o viewWillAppear para sincronização de estado entre telas: se o usuário pode ter alterado dados na tela anterior, este método é o local correto para atualizar a interface. Cada chamada ao viewWillAppear precede a aparição da tela, mesmo ao retornar de um controlador filho.
viewDidAppear notifica que a View apareceu completamente na tela e todas as animações de transição foram concluídas. Neste ponto, a tela está pronta para interação — o usuário vê a interface completa e pode interagir com ela. Este método é adequado para iniciar animações que devem começar após a aparição, iniciar temporizadores e rastrear impressões de análise.
Ao contrário do viewWillAppear, o viewDidAppear garante que a tela não só está visível mas também foi completamente renderizada. Se você iniciar uma animação no viewWillAppear, alguns quadros podem ser pulados porque o UIKit ainda não concluiu a transição. Para animações suaves, use viewDidAppear.
viewWillDisappear é chamado antes da View desaparecer da tela — ao fazer transição para outro controlador, fechar uma janela modal ou suspender o app. Este é o local adequado para salvar o estado, cancelar inscrição em notificações, parar processos ativos e liberar recursos que não são necessários quando a tela não está visível.
É importante lembrar: o viewWillDisappear não garante que a View desaparecerá de fato — o gesto pode ser cancelado. Portanto, salve dados críticos também no viewDidDisappear, que é chamado somente após o desaparecimento real.
viewDidDisappear completa o ciclo de aparição e desaparecimento. Ele é chamado após a View já estar oculta da tela. Neste método, as animações são finalmente paradas, os objetos temporários são removidos e o salvamento de dados iniciado no viewWillDisappear é confirmado.
Este método também precede o deinit do controlador — se seu UIViewController está sendo destruído, o viewDidDisappear será o último método do Lifecycle antes do deinit ser chamado. Use-o para a limpeza final que deve ocorrer antes do objeto ser destruído.
A sequência de chamadas depende de como a tela aparece: pela primeira vez, ao voltar, ou quando apresentada modalmente. Vamos considerar três cenários principais da perspectiva do UIKit.
Quando uma tela aparece pela primeira vez, o UIKit percorre o ciclo completo de criação: loadView é chamado, depois viewDidLoad, após o qual a animação de aparição começa. Durante a animação, viewWillAppear é chamado, e após a conclusão — viewDidAppear. Este é o único cenário onde todos os métodos de loadView a viewDidAppear são ativados sequencialmente.
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad — View carregada na memória")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear — Prestes a aparecer")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear — Tela completamente visível")
}
Quando o usuário volta para uma tela anterior, o UIKit não chama viewDidLoad novamente — a View já está carregada na memória. Em vez disso, apenas viewWillAppear e viewDidAppear são chamados na tela de retorno, e na atual — viewWillDisappear e viewDidDisappear. loadView e viewDidLoad são pulados já que a tela já existe na pilha de navegação.
A apresentação modal segue as mesmas regras: o novo controlador passa pelo ciclo completo na primeira aparição, enquanto o atual recebe viewWillDisappear e viewDidDisappear. Ao fazer dismiss, a ordem é invertida: o controlador que retorna obtém viewWillAppear e viewDidAppear novamente, enquanto o dispensado recebe os métodos finais. Este comportamento é uniforme para todos os tipos de transição no UIKit.
Vamos ver quatro cenários-chave onde a compreensão do Lifecycle impacta diretamente a qualidade do código e a experiência do usuário. Para cada cenário, fornecemos um exemplo com recomendações.
viewDidLoad é o local para a configuração inicial que não depende da visibilidade da tela. Aqui você configura o collectionView, registra arquivos nib para as células, cria fontes de dados e layouts. Se você está carregando dados da rede, no viewDidLoad é melhor apenas iniciar a solicitação e atualizar a UI no viewWillAppear quando a tela estiver pronta para exibição.
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(
MyCell.self,
forCellReuseIdentifier: MyCell.identifier
)
viewModel.loadInitialData()
}
Use viewWillAppear para sincronização de dados toda vez que a tela aparecer. Por exemplo, se o usuário pode ter alterado configurações na tela anterior, aqui você atualiza os valores exibidos, recarrega a tabela e ajusta o estado da NavigationBar. Isso garante que a tela sempre mostre dados atualizados em qualquer cenário de navegação.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
navigationController?.setNavigationBarHidden(false, animated: animated)
}
viewDidAppear é ideal para iniciar animações que devem começar após o usuário ter visto a tela. Aqui você também envia eventos de análise: visualização de tela, inicio de onboarding ou reprodução de vídeo. Iniciar animações antes da transição estar completa leva a uma interface instável — o UIKit não tem tempo suficiente para preparar um número adequado de quadros.
No viewWillDisappear, você salva rascunhos, para temporizadores e cancela a inscrição do NotificationCenter. Este é o último momento em que a tela ainda está visível e acessível para operações que exigem contexto do usuário. Para dados críticos, use adicionalmente o viewDidDisappear como proteção contra gestos cancelados.
O uso incorreto dos métodos do ciclo de vida é uma das fontes mais frequentes de erros em apps iOS. Vamos ver os principais erros que os desenvolvedores cometem em diferentes estágios do trabalho com UIViewController.
O primeiro erro — criar subviews no init ou loadView ao usar Storyboard. Se você está usando Interface Builder, não sobrescreva loadView desnecessariamente. Criar uma View no loadView quando existe um storyboard resulta em ignorar o arquivo xib e obter uma tela vazia.
O segundo erro — inscrever-se em notificações de teclado no viewDidLoad sem cancelar a inscrição. Se você se inscreveu no UIResponder.keyboardWillShowNotification mas não cancelou a inscrição ao ocultar a tela, o bloco continuará sendo chamado mesmo após o deinit do controlador — isso é um vazamento de memória com potencial queda do app.
O terceiro erro — temporizadores e solicitações de rede iniciados antes da tela aparecer. Carregar imagens ou executar animações quando a View ainda não está visível é um desperdício de recursos. Mova as atualizações visuais para viewWillAppear ou viewDidAppear.
O quarto erro — salvar dados apenas no viewWillDisappear. Com um gesto de pop interativo, o usuário pode começar um deslize e cancelá-lo — o método foi chamado mas a tela não desapareceu. Duplique o salvamento crítico no viewDidDisappear ou no manipulador applicationDidEnterBackground.
Perguntas frequentes
Uma vez — após a View ser carregada na memória. Quando a tela aparece novamente, o viewDidLoad não é chamado. Se precisar recriar a View, o controlador deve ser destruído e criado novamente.
O UIKit requer a chamada de super.viewDidLoad para o ciclo de vida funcionar corretamente. Sem ela, podem ocorrer problemas com atualizações de layout e manipulação de transições. Sempre chame super como primeira ação dentro do método.
Não recomendado. Se o controlador é inicializado a partir do Storyboard, o UIKit carrega automaticamente a View do xib. Sobrescrever o loadView cancela este processo e seu storyboard será ignorado.
Inscreva-se no viewDidLoad ou viewWillAppear, e cancele a inscrição no viewWillDisappear ou viewDidDisappear, usando uma referência fraca a self para evitar vazamentos de memória com closures.
O force quit mata o processo abruptamente — o UIKit não tem tempo de chamar os métodos do Lifecycle. Para salvar dados, use a notificação UIApplication.willTerminateNotification no AppDelegate.
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