Procurando entender o ciclo de vida do iOS UIViewController

299

Você poderia me explicar a maneira correta de gerenciar o UIViewControllerciclo de vida?

Em particular, eu gostaria de saber como usar Initialize, ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnloade Disposemétodos em Mono Touch para uma UIViewControllerclasse.

Lorenzo B
fonte
Existe alguma informação ou link para OSX ViewController e WindowController? Por favor, compartilhe.
Anoop Vaidya

Respostas:

410

Todos esses comandos são chamados automaticamente nos momentos apropriados pelo iOS quando você carrega / apresenta / oculta o controlador de exibição. É importante observar que esses métodos estão associados UIViewControllere não a UIViewsi mesmos. Você não obterá nenhum desses recursos apenas usando a UIView.

Há uma excelente documentação no site da Apple aqui . Colocando simplesmente, porém:

  • ViewDidLoad- Chamado quando você cria a classe e carrega do xib. Ótimo para configuração inicial e trabalho único.

  • ViewWillAppear- Chamado logo antes da exibição da sua exibição, bom para ocultar / mostrar campos ou qualquer operação que você deseje que ocorra sempre que a exibição estiver visível. Como você pode alternar entre visualizações, isso será chamado sempre que sua visualização estiver prestes a aparecer na tela.

  • ViewDidAppear - Chamado após a exibição da exibição - ótimo lugar para iniciar animações ou carregar dados externos de uma API.

  • ViewWillDisappear/ DidDisappear- Mesma ideia que ViewWillAppear/ ViewDidAppear.

  • ViewDidUnload/ ViewDidDispose- No Objective-C, é aqui que você faz a limpeza e a liberação de material, mas isso é tratado automaticamente, de modo que você não precisa fazer muito aqui.

Jacob Knobel
fonte
86
Este texto é um pouco enganador, pois o ViewDidLoad não deve ser usado para trabalhos únicos. Pode ser chamado várias vezes se a visualização for descarregada devido à pouca memória e carregada novamente.
Ricky Helgesson
4
Na verdade, ViewDidLoad não é chamado quando você cria / inicializa o controlador de exibição. É chamado na primeira vez que você faz qualquer coisa relacionada à visão do controlador de visão. Por exemplo, adicione-o como uma sub-visualização, defina o quadro etc. Também é chamado, é claro, ao carregar de uma ponta.
Jason Grandelli
3
ViewDidAppear - Chamado após a exibição da exibição - ótimo local para iniciar animações ou carregar dados externos de uma API. Por que é um bom lugar para começar a carregar dados? Por que não viewDidLoad?
Anton Chikin
1
e o método loadView, se for chamado pela primeira vez quando uma ponta for carregada na memória antes de viewDidLoad ou não.
iHulk 20/09/14
@chakrit, este é um bom ponto - o viewDidAppear é um ótimo local para atualizar dados (se necessário). Eu discordo do KVO, porque ele pode causar atualizações indesejáveis ​​nas visualizações que nunca são realmente vistas por um usuário.
Anton Chikin
409

ATUALIZAÇÃO: O ViewDidUnload foi descontinuado no iOS 6, portanto, atualizei a resposta.

O ciclo de vida do UIViewController é diagramado aqui:

O ciclo de vida de um controlador de exibição, diagramado

A vantagem de usar o Xamarin Native / Mono Touch é que ele usa as APIs nativas e, portanto, segue o mesmo ciclo de vida do ViewController que você encontraria na documentação da Apple.

Haider
fonte
17
Onde viewWillLayoutSubviews e viewDidLayoutSubviews estão neste fluxograma?
Max_Power89
7
Este diagrama é impreciso. viewDidUnload está obsoleto desde o iOS6: stackoverflow.com/questions/12509102/...
occulus
2
Isso é realmente simplesmente errado . Outro exemplo de uma resposta simplesmente errada no SO, com o passar dos anos. A computação é altamente não estática.
Fattie 13/09/19
186

Esta é a versão mais recente do iOS (modificada com Xcode 9.3, Swift 4.1 ). Abaixo estão todos os estágios que tornam o ciclo de vida UIViewControllercompleto.

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

Deixe-me explicar todas essas etapas.

1 loadView

Este evento cria / carrega a visualização que o controlador gerencia. Ele pode carregar de um arquivo de ponta associado ou vazio UIViewse nulo foi encontrado. Isso torna um bom lugar para criar suas visualizações no código programaticamente.

É aqui que as subclasses devem criar sua hierarquia de visualização customizada se não estiverem usando uma ponta. Nunca deve ser chamado diretamente. Substitua esse método apenas quando você criar visualizações de modo programático e atribuir a visualização raiz à viewpropriedade Não chame super método quando substituir o loadView

2) loadViewIfNeeded

Se a visualização da corrente viewControllerainda não foi definida, esse método carregará a visualização, mas lembre-se de que isso estará disponível apenas no iOS> = 9.0. Portanto, se você suporta o iOS <9.0, não espere que ele entre em cena.

Carrega a visualização do controlador de visualização, se ainda não tiver sido definida.

3) viewDidLoad

O viewDidLoadevento é chamado apenas quando a visualização é criada e carregada na memória, mas os limites da visualização ainda não estão definidos. Este é um bom lugar para inicializar os objetos que o controlador de exibição usará.

Chamado após o carregamento da visualização. Para os controladores de exibição criados no código, isso é pós-loadView. Para controladores de exibição desarquivados de uma ponta, isso ocorre depois que a exibição é configurada.

4) viewWillAppear

Este evento notifica viewControllersempre que a exibição aparece na tela. Nesta etapa, a vista possui limites definidos, mas a orientação não está definida.

Chamado quando a exibição está prestes a se tornar visível. O padrão não faz nada.

5) viewWillLayoutSubviews

Esta é a primeira etapa do ciclo de vida em que os limites são finalizados. Se você não estiver usando restrições ou Layout automático, provavelmente desejará atualizar as subvisões aqui. Isso está disponível apenas no iOS> = 5.0. Portanto, se você suporta o iOS <5.0, não espere que ele entre em cena.

Chamado imediatamente antes do método layoutSubviews da visualização do controlador de exibição ser chamado. As subclasses podem ser implementadas conforme necessário. O padrão é um nop.

6 viewDidLayoutSubviews

Este evento notifica o controlador de exibição que as subvisões foram configuradas. É um bom lugar para fazer alterações nas subvisões depois que elas foram definidas. Isso está disponível apenas no iOS> = 5.0. Portanto, se você suporta o iOS <5.0, não espere que ele entre em cena.

Chamado logo após o método layoutSubviews da visualização do controlador de exibição ser chamado. As subclasses podem ser implementadas conforme necessário. O padrão é um nop.

7) viewDidAppear

O viewDidAppearevento é acionado depois que a visualização é apresentada na tela. O que o torna um bom local para obter dados de um serviço de back-end ou banco de dados.

Chamado quando a visualização foi totalmente transferida para a tela. O padrão não faz nada

8) viewWillDisappear

O viewWillDisappearevento é acionado quando a exibição apresentada viewControllerestá prestes a desaparecer, descartar, encobrir ou ocultar atrás de outra viewController. Este é um bom lugar para restringir as chamadas de rede, invalidar o timer ou liberar objetos vinculados a isso viewController.

Chamado quando a exibição é descartada, coberta ou oculta.

9 viewDidDisappear

Esta é a última etapa do ciclo de vida que qualquer pessoa pode abordar, pois esse evento é acionado logo após a exibição da apresentação viewControllerter sido desaparecida, descartada, coberta ou oculta.

Chamado depois que a vista foi descartada, coberta ou oculta de outra forma. O padrão não faz nada

Agora, de acordo com a Apple, ao implementar esses métodos, lembre-se de chamar a superimplementação desse método específico.

Se você subclassificar UIViewController, deverá chamar a super implementação deste método, mesmo se você não estiver usando um NIB. (Por conveniência, o método init padrão fará isso por você e especificará nulo para os argumentos de ambos os métodos.) Na NIB especificada, o proxy Proprietário do Arquivo deve ter sua classe definida na subclasse do controlador de exibição, com a saída de exibição conectado à vista principal. Se você chamar esse método com um nome de ponta nula, o -loadViewmétodo dessa classe tentará carregar uma NIB cujo nome seja o mesmo da classe do seu controlador de exibição. Se esse NIB de fato não existir, você deverá chamar -setView:antes de -viewser chamado ou substituir o -loadViewmétodo para configurar suas visualizações programaticamente.

Espero que isso tenha ajudado. Obrigado.

UPDATE - Como @ThomasW apontou no comentário viewWillLayoutSubviewse viewDidLayoutSubviewstambém será chamado em outros momentos quando subvistas da vista principal são carregadas, por exemplo, quando células de uma exibição de tabela ou coleção são carregadas.

ATUALIZAÇÃO - Como @Maria apontou dentro do comentário, a descrição de loadViewfoi atualizada

onCompletion
fonte
6
viewWillLayoutSubviewse viewDidLayoutSubviewstambém será chamado em outros momentos quando as subvisões da visualização principal forem carregadas, por exemplo, quando as células de uma visualização de tabela ou de coleção forem carregadas.
Thomasw
Há um pequeno engano nesta resposta: loadView () é sempre chamado, mas não deve ser substituído quando a visualização para o controlador criado no IB.
Maria
@ Maria Por favor, vá em frente e edite a resposta se achar que pode ser melhorada. Obrigado.
OnCompletion 15/1018
O padrão não faz nada errado viewWillAppear viewDidAppear viewDidDisappear. Você deve chamar super em algum momento.
Mick
47

iOS 10,11 (Swift 3.1, Swift 4.0)

De acordo com UIViewControllera UIKitdesenvolvedores,

1. loadView ()

É aqui que as subclasses devem criar sua hierarquia de exibição personalizada se não estiverem usando uma ponta . Nunca deve ser chamado diretamente.

2. loadViewIfNeeded ()

Carrega a visualização do controlador de visualização, se ainda não tiver sido definida.

3. viewDidLoad ()

Chamado após o carregamento da visualização. Para os controladores de exibição criados no código, isso é pós-loadView. Para controladores de exibição desarquivados de uma ponta, isso ocorre depois que a exibição é configurada.

4. viewWillAppear (_ animado: Bool)

Chamado quando a exibição está prestes a se tornar visível. O padrão não faz nada

5. viewWillLayoutSubviews ()

Chamado imediatamente antes do método layoutSubviews da visualização do controlador de exibição ser chamado. As subclasses podem ser implementadas conforme necessário. O padrão não faz nada.

6. viewDidLayoutSubviews ()

Chamado logo após o método layoutSubviews da visualização do controlador de exibição ser chamado. As subclasses podem ser implementadas conforme necessário. O padrão não faz nada.

7. viewDidAppear (_ animado: Bool)

Chamado quando a visualização foi totalmente transferida para a tela. O padrão não faz nada

8. viewWillDisappear (_ animado: Bool)

Chamado quando a exibição é descartada, coberta ou oculta. O padrão não faz nada

9. viewDidDisappear (_ animado: Bool )

Chamado depois que a vista foi descartada, coberta ou oculta de outra forma. O padrão não faz nada

10. viewWillTransition (no tamanho: CGSize, com coordenador: UIViewControllerTransitionCoordinator)

Chamado quando a exibição está em transição.

11. willMove (pai toParentViewController: UIViewController?)

12. didMove (pai toParentViewController: UIViewController?)

Esses dois métodos são públicos para que as subclasses de contêiner chamem ao fazer a transição entre controladores filhos. Se eles forem substituídos, as substituições devem garantir a chamada de super.

O argumento pai em ambos os métodos é nulo quando um filho está sendo removido de seu pai; caso contrário, é igual ao novo controlador de exibição pai.

13. didReceiveMemoryWarning ()

Chamado quando o aplicativo pai recebe um aviso de memória. No iOS 6.0, ele não limpa mais a exibição por padrão.

Rajamohan S
fonte
2
É realmente muito bom que o stackoverflow não elimine todas as respostas erradas e incompletas de todo esse segmento. Sua resposta parece completa no que diz respeito às chamadas de método, por isso vou assumir que a sua está correta e trabalhar com isso.
Logicsaurus Rex
O que é um nibcomo mencionado abaixo loadView?
Petrus Theron
2
@LogicsaurusRex Concordo. Da mesma maneira que o SO marca as perguntas como duplicadas ou protegidas, acho que deve poder marcar as respostas como desatualizadas ou obsoletas
rmp251
O ponto 5 acima está errado. viewWillLayoutSubviews()é chamado antes que o objeto de exibição do ViewController invoque seu layoutSubviews()método
williamukoh
28

A partir do iOS 6 em diante. O novo diagrama é o seguinte:

insira a descrição da imagem aqui

Saad
fonte
1
Chame essa visualização de "A". Considere uma segunda visualização "B" que aparece enquanto "A" desaparece. O "B.viewWillAppear" é anterior ou posterior ao "A.viewDidDisappear"? E existem situações em que a ordem dessas duas mudanças?
Página
Parece que o willApear da nova visualização (B) será chamado antes do desaparecimento. Para segunda pergunta. Precisa de algum tempo para investigar.
Saad
21

Vamos nos concentrar nos métodos responsáveis ​​pelo ciclo de vida do UIViewController :

  • Criação:

    - (void)init

    - (void)initWithNibName:

  • Ver criação:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

    - (UIView *)initWithCoder:(NSCoder *)coder

  • Tratamento da alteração do estado da exibição:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload

  • Tratamento de aviso de memória:

    - (void)didReceiveMemoryWarning

  • Desalocação

    - (void)viewDidUnload

    - (void)dealloc

Diagrama do ciclo de vida do UIViewController

Para obter mais informações, consulte a Referência de classe UIViewController .

Alexey Pelekh
fonte
19

Os métodos viewWillLayoutSubviewse viewDidLayoutSubviewsnão são mencionados nos diagramas, mas são chamados entre viewWillAppeare viewDidAppear. Eles podem ser chamados várias vezes.

gjgjgj
fonte
Eles também serão chamados em outros momentos quando as subvisões da visualização principal forem carregadas, por exemplo, quando as células de uma visualização de tabela ou coleção são carregadas.
Thomasw
16

A resposta de Haider está correta no pré-iOS 6. No entanto, a partir do iOS 6, viewDidUnload e viewWillUnload nunca são chamados. Os documentos afirmam: "As visualizações não são mais eliminadas em condições de pouca memória e, portanto, esse método nunca é chamado".

Matt Becker
fonte
Tentei colocar um ponto de interrupção em ViewWillDisappear, ViewDidDisappear, Dispose. Mas nenhum deles estava sendo chamado quando naveguei com o método PresentViewController (). Qual seria a razão ?
Sreeraj
1
O link não funciona ... Então, o que o sistema operacional faz com pouca memória?
Filho
Salva-os em disco?
Ian Warburton
16

Há muitas informações desatualizadas e incompletas aqui. Apenas para iOS 6 e versões mais recentes :

  1. loadView[uma]
  2. viewDidLoad[uma]
  3. viewWillAppear
  4. viewWillLayoutSubviews é a primeira vez que os limites são finalizados
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[b]
  8. * viewDidLayoutSubviews[b]

Notas de rodapé:

(a) - Se você nil manualmente o seu ponto de vista durante didReceiveMemoryWarning, loadViewe viewDidLoadserá chamado novamente. Ou seja, por padrão loadViewe viewDidLoadsó é chamado uma vez por instância do controlador de exibição.

(b) Pode ser chamado de 0 ou mais vezes.

bobics
fonte
1
viewWillLayoutSubviewse viewDidLayoutSubviewstambém será chamado em outros momentos quando as subvisões da visualização principal forem carregadas, por exemplo, quando as células de uma visualização de tabela ou de coleção forem carregadas.
Thomasw
11

Explicando as transições de estado no documento oficial: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

Esta imagem mostra as transições de estado válidas entre vários métodos de retorno de chamada 'will' e 'did'

Transições de estado válidas:


Retirado de: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Art/UIViewController Referência de Classe_2x.png

Luismi
fonte
0

Conforme o documento da Apple - Comece a desenvolver aplicativos iOS (Swift) - Trabalhe com os controladores de exibição - Compreenda o ciclo de vida do controlador de exibição

viewDidLoad()- Chamado quando a exibição de conteúdo do controlador de exibição (a parte superior de sua hierarquia de exibição) é criada e carregada a partir de um storyboard. … Use este método para executar qualquer configuração adicional exigida pelo seu controlador de exibição.

viewWillAppear()- Chamado imediatamente antes da visualização de conteúdo do controlador de exibição ser adicionada à hierarquia de exibição do aplicativo. Use este método para acionar quaisquer operações que precisem ocorrer antes que a exibição do conteúdo seja apresentada na tela

viewDidAppear()- Chamado logo após a exibição de conteúdo do controlador de exibição ter sido adicionada à hierarquia de exibição do aplicativo. Use este método para acionar quaisquer operações que precisem ocorrer assim que a exibição for apresentada na tela, como buscar dados ou mostrar uma animação.

viewWillDisappear()- Chamado imediatamente antes da exibição do conteúdo do controlador de exibição ser removida da hierarquia de exibição do aplicativo. Use este método para executar tarefas de limpeza, como confirmar alterações ou renunciar ao status de primeiro respondedor.

viewDidDisappear()- Chamado logo após a exibição do conteúdo do controlador de exibição ter sido removida da hierarquia de exibição do aplicativo. Use este método para executar atividades adicionais de desmontagem.

fred
fonte