Il existe de nombreuses méthodes pour remplacer, comme initWithNibname:
, awakeFromNib
, loadView
, viewDidLoad
, viewDidAppear:
, layoutSubviews
, et je ne peux tout simplement pas décider dans quel ordre ces méthodes seront appelées.
Je viens de remplacer l'un d'eux "par cœur".
Une explication détaillée?
Il se passe beaucoup de choses dans les coulisses avec Cocoa view et viewController management .
1. L'objet viewController
À sa base, un viewController est un objet contrôleur générique. Lorsqu'il est alloué pour la première fois à un objet initialisé, aucun objet de vue ne lui est associé. La vue n'est instanciée que lorsque (et si) elle est requise. Ainsi, sans tenir compte de la vue, le cycle de vie d'un viewController est le même que tout autre objet:
UIViewController * myVC = [[UIViewController alloc] initWith...];
...
[myVC release];
L'initialiseur désigné pour viewControllers est -initWithNibname:bundle:
. Si vous spécifiez une pointe, le viewController peut charger automatiquement sa vue à partir de cette pointe et connecter les IBOutlets que vous avez définies (voir ci-dessous pour plus de détails).
2. Chargement et déchargement de la vue
Un viewController chargera sa vue selon les besoins. Cela se produit généralement lorsque le -view
est appelée pour la première fois et peut se produire à tout moment dans votre programme, selon la façon dont vous initialisez votre interface utilisateur. La vue peut également être détruite et rechargée plusieurs fois pendant la durée de vie de votre programme, selon la façon dont vous gérez votre interface utilisateur. Lorsque le viewController a identifié que sa vue est requise mais pas encore chargée, le -loadView
sera appelée. Le flux de messages de base se présente comme suit:
view
loadView
viewDidLoad
Notez que si vous remplacez le -view
méthode, -loadView
et viewDidLoad
ne seront pas appelés automatiquement. Si vous remplacez -loadView
, you must définissez la propriété view
de viewController. Sinon, le prochain appel à -view
déclenchera à nouveau le processus de chargement.
La vue peut également être déchargée à tout moment pendant la durée de vie de votre programme simplement en définissant la propriété view
sur nil
. L'implémentation par défaut de -didReceiveMemoryWarning
le fera automatiquement, tant que la vue n'a pas de vue d'ensemble (c'est-à-dire si elle ne fait pas actuellement partie de la hiérarchie de vue active). Le flux de messages se déroule comme suit:
view = nil
viewDidUnload
2a. Chargement de la vue par programme
Si vous choisissez de remplacer -loadView
, vous pouvez créer une vue, des sous-vues, d'autres viewControllers et toutes les connexions entre ces objets comme bon vous semble. Bien sûr, cela signifie que vous êtes également responsable de la gestion de la mémoire en ce qui concerne les objets que vous créez. Si votre sous-classe remplace -loadView
, il doit être initialisé en utilisant nil
pour nibName
et bundle
.
2b. Chargement de la vue depuis une plume
Si vous utilisez un fichier nib, l'implémentation par défaut de -loadView
ouvrira automatiquement ce fichier nib, instanciera ses objets, ajoutera toutes les connexions entre eux et prendra soin de la gestion de la mémoire pour vous.
Les choses deviennent un peu plus délicates avec les fichiers nib, car il se passe tellement de choses en arrière-plan. Le -awakeFromNib
est appelée pour chaque objet qui est instanciée lorsqu'un fichier nib est chargé, et il n'y a aucune garantie que les autres objets du fichier nib auront été entièrement chargés lors de son appel.
3. Affichage des vues
-viewWillAppear:
, -viewDidAppear:
, -viewWillDisappear:
et -viewDidDisappear:
ne sont appelés que lorsque la vue est affichée ou masquée à l'écran, en particulier pendant les transistions animées d'une vue à l'autre. Ces méthodes peuvent être appelées plusieurs fois pendant la durée de vie de votre programme, car les vues sont échangées dans et hors de votre schéma de navigation.
4. Afficher la disposition
Le -layoutSubviews
la méthode est pas partie de UIViewController
. Il est appelé pour les objets UIView
lorsque leurs limites ont été modifiées. Si vous utilisez une sous-classe UIView
personnalisée dans votre programme, cette méthode peut être utilisée pour créer une présentation de sous-vue personnalisée au lieu de s'appuyer sur les méthodes de redimensionnement automatique par défaut de Cocoa.
5. Tout mettre ensemble
En raison de la complexité, il existe de nombreuses façons différentes pour que ce processus se produise, mais un calendrier normal pourrait ressembler à ceci:
-[viewController initWithNibname:Bundle:]
-[viewController awakeFromNib]
-[viewController loadView]
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear] // user navigated away
-[viewController viewDidDisappear]
...
-[viewController viewWillAppear] // user navigated back
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear] // user navigated away
-[viewController viewDidDisappear]
...
-[viewController setView:nil] // memory warning, perhaps
-[viewController viewDidUnload]
...
-[viewController loadView] // user navigated back
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
J'ai revisité ces derniers temps et créé un projet de test: https://github.com/Janek2004/ViewControllerTest
Exécutez le projet sur le simulateur iOS pour voir l'ordre d'exécution des méthodes de la sous-classe UIViewController. L'ordre peut être différent chaque fois que nous utilisons le fichier Nib au lieu du storyboard ou du contrôleur de vue par programme.
- [ViewController viewDidAppear:] Avertit le contrôleur de vue que sa vue a été ajoutée à une hiérarchie de vues. Vous pouvez remplacer cette méthode pour effectuer des tâches supplémentaires associées à la présentation de la vue.
- [ViewController viewWillDisappear:] Avertit le contrôleur de vue que sa vue est sur le point d'être supprimée d'une hiérarchie de vues. Cette méthode est appelée en réponse à une vue en cours de suppression d'une hiérarchie de vues. Cette méthode est appelée avant la suppression effective de la vue et avant la configuration des animations. Avertit le contrôleur de vue que sa vue a été ajoutée à une hiérarchie de vues. Vous pouvez remplacer cette méthode pour effectuer des tâches supplémentaires associées à la présentation de la vue.
Un autre moment clé du processus est lorsque layoutSubviews est appelé sur n'importe quelle sous-vue. C'est à ce stade, et pas plus tôt, que les contraintes configurées dans le storyboard ont été appliquées. Si vous devez apporter des ajustements aux sous-vues d'une vue, en fonction de ses coordonnées contraintes, vous devez le faire dans layoutSubviews. Si vous le faites dans viewDidLayoutSubviews, ce sera trop tôt, car ces sous-vues n'ont pas encore appliqué leurs contraintes (car, comme le dit la documentation "Chaque sous-vue est responsable de l'ajustement de sa propre disposition".) Et si vous le faites dans viewDidAppear, ce sera trop tard évidemment, car l'utilisateur verra vos sous-vues changer les coordonnées. Ainsi, l'autre étape vitale du processus est:
-viewController viewWillAppear
-viewController viewWillLayoutSubviews
-viewController viewDidLayoutSubviews
---> viewController.[any subview] layoutSubviews
-viewController viewDidAppear
de Apple documentation UIViewController:
Lorsque vous définissez une nouvelle sous-classe de UIViewController, vous devez spécifier les vues à gérer par le contrôleur. Il existe deux façons mutuellement exclusives de spécifier ces vues: manuellement ou à l'aide d'un fichier nib. Si vous spécifiez les vues manuellement, vous devez implémenter la méthode loadView et l'utiliser pour affecter un objet de vue racine à la propriété view. Si vous spécifiez des vues à l'aide d'un fichier nib, vous ne devez pas remplacer loadView, mais plutôt créer un fichier nib dans Interface Builder, puis initialiser votre objet contrôleur de vue à l'aide de la méthode initWithNibName: bundle:. La création de vues à l'aide d'un fichier nib est souvent plus simple car vous pouvez utiliser l'application Interface Builder pour créer et configurer vos vues graphiquement (par opposition à un programme). Cependant, les deux techniques ont le même résultat final, qui consiste à créer l'ensemble approprié de vues et à les exposer via la propriété view.
Du haut de ma tête:
aucun indice où layoutSubviews entre
Je résout généralement cette question en mettant un NSLog (ou des points d'arrêt) dans tous ces délégués, y compris le délégué de lancement de l'application, et en suivant l'ordre dans le débogueur.
- Ceci est lié à l'affichage uniquement: - viewWillAppear: - viewDidAppear: - viewWillDisappear: et - viewDidDisappear: ne sont appelés que lorsque la vue est affichée. - viewController viewDidLoad - viewController viewWillAppear - viewController viewDidAppear autres méthodes - viewController viewDidDisappear - viewController viewWillDisappear - viewController viewDidUnload
Je tiens à remercier e.James pour son excellente description. Je ne peux pas encore commenter un message, mais pour une illustration visuelle rapide, reportez-vous à cet organigramme dans le guide de programmation de View Controller. Et je me rends compte que c'est hors sujet, mais pour un graphique de la séquence de lancement de l'application , reportez-vous au Guide de programmation d'application iOS.