Como o View Controller Containment funciona no iOS 5?

108

Na WWDC 2011 Sessão 102, a Apple introduziu View Controller contenção, que é a capacidade de criar recipientes controlador de exibição personalizada, análogo a UITabBarController, UINavigationControllere afins.

Assisti aos exemplos várias vezes. Há uma enxurrada de métodos associados a esse padrão, mas foi um pouco difícil descobri-los exatamente. Vou postar aqui o que acho que está acontecendo e ver se a comunidade confirma ou desconfirma minhas suspeitas.

Cenário 1: Mudança de nenhum pai para um novo controlador de visualização pai

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

As duas primeiras linhas devem ocorrer na ordem indicada ou podem ser invertidas?

Cenário 2: Mover de um controlador de visão pai para nenhum controlador de visão pai

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

Também é necessário ligar [vc didMoveToParentViewController:nil]? Os exemplos na Sessão 102 não fizeram isso neste cenário, mas não sei se isso foi uma omissão ou não.

Cenário 3: Movendo de um controlador de visão pai para outro

Isso provavelmente ocorrerá da seguinte maneira, porque a lógica em cada controlador de visualização pai será encapsulada.

// In the old parent
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

// In the new parent
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];

Questões

Minha principal pergunta é: É assim que a contenção do controlador de visualizações deve funcionar, em geral? A mecânica fornecida acima está correta?

É necessário ligar willMoveToParentViewControllerantes de ligar addChildViewController? Esta parece ser a ordem lógica para mim, mas é estritamente necessária?

É necessário ligar didMoveToParentViewController:nildepois de ligar removeFromParentViewController?

Gregory Higley
fonte

Respostas:

72

Os UIViewControllerdocumentos são bastante claros sobre quando e quando não chamar willMove/ didMovemétodos. Confira a documentação "Implementando um controlador de visualização de contêiner" .

Os documentos dizem que, se você não substituir addChildViewController, não precisa chamar o willMoveToParentViewController:método. No entanto, você precisa chamar o didMoveToParentViewController:método após a conclusão da transição. "Da mesma forma, é responsabilidade do controlador de visualização do contêiner chamar o willMoveToParentViewController:método antes de chamar o removeFromParentViewControllermétodo. O removeFromParentViewControllermétodo chama o didMoveToParentViewController:método do controlador de visualização filho."

Além disso, há um exemplo trabalhado aqui e um código de amostra aqui .

Boa sorte

Timthetoolman
fonte
17
Eu vejo, então addChildViewControllerdeve ser equilibrado com didMoveToParentViewControllere willMoveToParentViewControllerdeve ser equilibrado com removeFromParentViewController. Isso é exatamente o que eu estava procurando. Não tenho certeza de como eu perdi isso nos documentos.
Gregory Higley
Por que não? Por que você não precisa chamar willMoveToParentViewController, mas tem que chamar didMoveToParentViewController?
user4951
Porque é isso que os médicos dizem. A Apple obviamente sente que não precisamos saber.
7
A razão é pela animação: digamos que você esteja criando seu próprio controlador de navegação. No início de uma animação slide-in, 'willMove' precisa ser chamado e, no final da animação, 'didMove' precisa ser chamado. Agora, quando você chama 'addChild' no início da animação, ele chama automaticamente 'willMove' para você. Mas não pode saber quando a animação (se houver) termina, então você tem que chamar 'didMove' manualmente no final da animação (ou imediatamente em nenhuma animação).
Chris
2
E como para uma animação 'slide out', por exemplo, a criança está sendo removida, você tem que chamar 'willMove' manualmente no início da animação, porque de outra forma o uikit não saberia quando chamar o VC de seu filho 'viewWillDisappear'. E no final da animação, quando você chama removeFromParentViewController, ele pode chamar 'didMove' automaticamente para você.
Chris
23

Esta parte não está correta:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

De acordo com a documentação:

Quando seu contêiner personalizado chama o método addChildViewController :, ele chama automaticamente o método willMoveToParentViewController: do controlador de visualização a ser adicionado como filho antes de adicioná-lo.

Então você não precisa da [vc willMoveToParentViewController:self]ligação. Isso é feito automaticamente quando você liga [self addChildViewController:vc]. Aqui está o exemplo de código novamente:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Para remover controladores de visualização:

O método removeFromParentViewController chama automaticamente o método didMoveToParentViewController: do controlador de visualização filho após remover o filho.

Presumivelmente, esta chamada é [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically
Nevan King
fonte
parece que, se feito de outra forma, mesmo que pareça funcionar, PresentViewController não está definido no appearViewController.
Adrian
Os documentos dizem chamar didMoveToParentViewController " imediatamente após chamar o método addChildViewController:", mas não especifica quando você realmente adiciona a subvisualização filha. Eu me pergunto se todos entenderam isso errado. Existe um exemplo em alguns Apple Docs que podemos comparar com isso?
Robert
Nota: você fazer necessidade de chamar willMoveToParentViewControllerantes addChildViewControllerse o item que você está em movimento é uma classe personalizada com substituído addChildViewController(a menos que seu substituir o chama internamente)
bunkerdive