Je me lance juste pour la première fois dans le développement iOS, et l'une des premières choses que j'ai eu à faire est d'implémenter un contrôleur de vue de conteneur personnalisé - appelons-le SideBarViewController
- qui permute lequel de plusieurs contrôleurs de vue enfants possibles il montre, presque exactement comme un contrôleur de barre d'onglets standard . (C'est à peu près un contrôleur de barre d'onglets mais avec un menu latéral masquable au lieu d'une barre d'onglets.)
Conformément aux instructions de la documentation Apple, j'appelle addChildViewController
chaque fois que j'ajoute un ViewController enfant à mon conteneur. Mon code pour échanger le contrôleur de vue enfant actuel affiché par le SideBarViewController
ressemble à ceci:
- (void)showViewController:(UIViewController *)newViewController {
UIViewController* oldViewController = [self.childViewControllers
objectAtIndex:0];
[oldViewController removeFromParentViewController];
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self addChildViewController: newViewController];
[self.view addSubview: newViewController.view];
}
Ensuite, j'ai commencé à essayer de comprendre ce que addChildViewController
fait ici et j'ai réalisé que je n'en avais aucune idée. En plus de coller le nouveau ViewController
dans le .childViewControllers
tableau, il semble n'avoir aucun effet sur quoi que ce soit. Les actions et les prises de la vue du contrôleur enfant vers le contrôleur enfant que j'ai défini sur le storyboard fonctionnent toujours très bien même si je n'appelle jamais addChildViewController
, et je ne peux pas imaginer ce que cela pourrait affecter d'autre.
En effet, si je réécris mon code pour ne pas appeler addChildViewController
, et plutôt ressembler à ça ...
- (void)showViewController:(UIViewController *)newViewController {
// Get the current child from a member variable of `SideBarViewController`
UIViewController* oldViewController = currentChildViewController;
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self.view addSubview: newViewController.view];
currentChildViewController = newViewController;
}
... alors mon application fonctionne toujours parfaitement, pour autant que je sache!
La documentation Apple n'éclaire pas beaucoup sur ce que addChildViewController
fait, ou pourquoi nous sommes censés l'appeler. Toute l'étendue de la description pertinente de ce que fait la méthode ou pourquoi elle devrait être utilisée dans sa section dans la UIViewController
référence de classe est, à l'heure actuelle:
Ajoute le contrôleur de vue donné en tant qu'enfant. ... Cette méthode est uniquement destinée à être appelée par une implémentation d'un contrôleur de vue de conteneur personnalisé. Si vous remplacez cette méthode, vous devez appeler super dans votre implémentation.
Il y a aussi ce paragraphe plus tôt sur la même page:
Votre contrôleur de vue de conteneur doit associer un contrôleur de vue enfant à lui-même avant d'ajouter la vue racine de l'enfant à la hiérarchie de vues. Cela permet à iOS d'acheminer correctement les événements vers les contrôleurs de vue enfants et les vues que ces contrôleurs gèrent. De même, après avoir supprimé la vue racine d'un enfant de sa hiérarchie de vues, il doit déconnecter ce contrôleur de vue enfant de lui-même. Pour créer ou annuler ces associations, votre conteneur appelle des méthodes spécifiques définies par la classe de base. Ces méthodes ne sont pas destinées à être appelées par les clients de votre classe de conteneur; ils doivent être utilisés uniquement par l'implémentation de votre conteneur pour fournir le comportement de confinement attendu.
Voici les méthodes essentielles que vous pourriez avoir besoin d'appeler:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
mais il n'offre aucun indice sur ce que sont les «événements» ou le «comportement de confinement attendu» dont il parle, ni pourquoi (ou même quand) appeler ces méthodes est «essentiel».
Les exemples de contrôleurs de vue de conteneur personnalisés dans la section "Contrôleurs de vue de conteneur personnalisés" de la documentation Apple appellent tous cette méthode, donc je suppose qu'elle sert un objectif important au-delà de simplement faire apparaître le ViewController enfant sur un tableau, mais je ne peux pas comprendre quel est cet objectif. Que fait cette méthode et pourquoi devrais-je l'appeler?
la source
Réponses:
Je me posais aussi des questions sur cette question. J'ai regardé la session 102 des vidéos de la WWDC 2011 et M. View Controller, Bruce D. Nilo , a dit ceci:
Il semble donc que l'appel à
addChildViewController:
fait très peu. Les effets secondaires de l'appel sont la partie importante. Ils viennent des relationsparentViewController
etchildViewControllers
. Voici quelques-uns des effets secondaires que je connais:transitionFromViewController:toViewController:…
lorsque les deux VC doivent avoir le même parentnavigationController
,tabBarController
propriétés , etc.la source
Je pense qu'un exemple vaut mille mots.
Je travaillais sur une application de bibliothèque et je voulais afficher une belle vue du bloc-notes qui apparaît lorsque l'utilisateur souhaite ajouter une note.
Après avoir essayé quelques solutions, j'ai fini par inventer ma propre solution personnalisée pour afficher le bloc-notes. Ainsi, lorsque je veux afficher le bloc-notes, je crée une nouvelle instance de
NotepadViewController
et ajoute sa vue racine en tant que sous-vue à la vue principale. Jusqu'ici tout va bien.Ensuite, j'ai remarqué que l'image du bloc-notes est partiellement cachée sous le clavier en mode paysage.
J'ai donc voulu changer l'image du bloc-notes et la décaler. Et pour ce faire, j'ai écrit le code approprié dans la
willAnimateRotationToInterfaceOrientation:duration:
méthode, mais lorsque j'ai exécuté l'application, rien ne s'est passé! Et après le débogage, j'ai remarqué qu'aucune desUIViewController
méthodes de rotation de s 'est réellement appeléeNotepadViewController
. Seules ces méthodes du contrôleur de vue principal sont appelées.Pour résoudre ce problème, j'avais besoin d'appeler toutes les méthodes
NotepadViewController
manuellement lorsqu'elles sont appelées dans le contrôleur de vue principal. Cela compliquera bientôt les choses et créera une dépendance supplémentaire entre les composants non liés de l'application.C'était dans le passé, avant l'introduction du concept de contrôleurs de vue enfants. Mais maintenant, il vous suffit d'
addChildViewController
accéder au contrôleur de vue principal et tout fonctionnera comme prévu sans plus de travail manuel.Modifier: il existe deux catégories d'événements qui sont transférés aux contrôleurs de vue enfants:
1- Méthodes d'apparence:
2- Méthodes de rotation:
Vous pouvez également contrôler les catégories d'événements que vous souhaitez transférer automatiquement en remplaçant
shouldAutomaticallyForwardRotationMethods
etshouldAutomaticallyForwardAppearanceMethods
.la source
addChildViewController
au contrôleur parent.-[UIViewController addChildViewController:]
ajoute uniquement le contrôleur de vue passé dans un tableau de viewControllers dont un viewController (le parent) souhaite conserver la référence. Vous devez en fait ajouter vous-même les vues de viewController à l'écran en les ajoutant en tant que sous-vues d'une autre vue (par exemple la vue de parentViewController). Il existe également un objet pratique dans Interface Builder pour utiliser childrenViewControllers dans les storyboards.Auparavant, pour garder la référence des autres viewControllers dont vous utilisiez les vues, vous deviez en garder une référence manuelle dans @properties. Avoir une propriété intégrée comme
childViewControllers
et par conséquentparentViewController
est un moyen pratique de gérer de telles interactions et de créer des viewControllers composés tels que UISplitViewController que vous trouvez sur les applications iPad.De plus, les childrenViewControllers reçoivent également automatiquement tous les événements système que le parent reçoit: -viewWillAppear, -viewWillDisappear, etc. Auparavant, vous auriez dû appeler ces méthodes manuellement sur vos "childrenViewControllers".
C'est tout.
la source
iOS "system events"
ne jette pas grand-chose; cela ne semble pas être un terme utilisé par Apple?