Vous cherchez à comprendre le cycle de vie iOS UIViewController

299

Pourriez-vous m'expliquer la bonne façon de gérer le UIViewControllercycle de vie?

En particulier, je voudrais savoir comment utiliser Initialize, ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnloadet Disposeméthodes Mono tactile pour une UIViewControllerclasse.

Lorenzo B
la source
Existe-t-il des informations ou un lien pour OSX ViewController et WindowController? Veuillez le partager.
Anoop Vaidya

Réponses:

410

Toutes ces commandes sont appelées automatiquement aux moments appropriés par iOS lorsque vous chargez / présentez / masquez le contrôleur de vue. Il est important de noter que ces méthodes sont attachées à elles-mêmes UIViewControlleret non à UIViewelles-mêmes. Vous n'obtiendrez aucune de ces fonctionnalités en utilisant simplement a UIView.

Il y a une excellente documentation sur le site d'Apple ici . Mettre tout simplement si:

  • ViewDidLoad- Appelé lorsque vous créez la classe et chargez à partir de xib. Idéal pour la configuration initiale et le travail ponctuel.

  • ViewWillAppear- Appelé juste avant l'affichage de votre vue, idéal pour masquer / afficher des champs ou toute opération que vous souhaitez effectuer à chaque fois avant que la vue ne soit visible. Étant donné que vous pouvez faire des allers-retours entre les vues, cela sera appelé chaque fois que votre vue est sur le point d'apparaître à l'écran.

  • ViewDidAppear - Appelé après l'affichage de la vue - endroit idéal pour démarrer une animation ou le chargement de données externes à partir d'une API.

  • ViewWillDisappear/ DidDisappear- Même idée que ViewWillAppear/ ViewDidAppear.

  • ViewDidUnload/ ViewDidDispose- Dans Objective-C, c'est là que vous effectuez votre nettoyage et la sortie des trucs, mais cela est géré automatiquement, donc pas grand-chose à faire ici.

Jacob Knobel
la source
86
Ce texte est légèrement trompeur, car ViewDidLoad ne doit pas être utilisé pour un travail unique. Il peut être appelé plusieurs fois si la vue est déchargée en raison d'une mémoire insuffisante, puis rechargée.
Ricky Helgesson
4
ViewDidLoad n'est pas réellement appelé lorsque vous créez / initialisez le contrôleur de vue. Il est appelé la première fois que vous effectuez une opération liée à la vue du contrôleur de vue. Comme l'ajouter en tant que sous-vue, définir le cadre, etc. Il est également appelé bien sûr lors du chargement à partir d'une pointe.
Jason Grandelli
3
ViewDidAppear - Appelé après l'affichage de la vue - endroit idéal pour démarrer une animation ou le chargement de données externes à partir d'une API. Pourquoi est-ce un bon endroit pour commencer à charger des données? Pourquoi pas viewDidLoad?
Anton Chikin
1
Qu'en est-il de la méthode loadView, si elle est appelée la première fois lorsqu'une plume est chargée en mémoire avant viewDidLoad ou non.
iHulk
@chakrit c'est un bon point - viewDidAppear est un excellent endroit pour actualiser les données (si vous en avez besoin). Je ne suis pas d'accord avec KVO, car il peut provoquer des rafraîchissements indésirables sur les vues qui ne sont jamais réellement vues par un utilisateur.
Anton Chikin
409

MISE À JOUR: ViewDidUnload a été déconseillé dans iOS 6, donc mis à jour la réponse en conséquence.

Le cycle de vie d'UIViewController est schématisé ici:

Le cycle de vie d'un contrôleur de vue, schématisé

L'avantage d'utiliser Xamarin Native / Mono Touch, c'est qu'il utilise les API natives, et il suit donc le même cycle de vie de ViewController que vous trouveriez dans la documentation d'Apple.

Haider
la source
17
Où vont viewWillLayoutSubviews et viewDidLayoutSubviews sur cet organigramme?
Max_Power89
7
Ce diagramme est inexact. viewDidUnload est obsolète depuis iOS6: stackoverflow.com/questions/12509102/…
occulus
2
C'est en effet tout simplement faux . Un autre exemple d'une réponse simplement fausse sur SO, au fil des ans. L'informatique est hautement non statique.
Fattie
186

Il s'agit des dernières versions d'iOS (modifiées avec Xcode 9.3, Swift 4.1 ). Voici toutes les étapes qui rendent le cycle de vie UIViewControllercomplet.

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

Permettez-moi d'expliquer toutes ces étapes.

1. loadView

Cet événement crée / charge la vue gérée par le contrôleur. Il peut se charger à partir d'un fichier nib associé ou d'un vide UIViewsi null a été trouvé. Cela en fait un bon endroit pour créer vos vues dans le code par programme.

C'est là que les sous-classes doivent créer leur hiérarchie de vue personnalisée si elles n'utilisent pas de plume. Ne devrait jamais être appelé directement. Ne remplacez cette méthode que lorsque vous créez des vues par programme et affectez la vue racine à la viewpropriété N'appelez pas de super méthode lorsque vous substituez loadView

2. loadViewIfNeeded

Si au cas où la vue du courant viewControllern'a pas encore été définie, cette méthode chargera la vue, mais rappelez-vous, cela n'est disponible que dans iOS> = 9.0. Donc, si vous prenez en charge iOS <9.0, ne vous attendez pas à ce qu'il apparaisse dans l'image.

Charge la vue du contrôleur de vue si elle n'a pas déjà été définie.

3. viewDidLoad

L' viewDidLoadévénement n'est appelé que lorsque la vue est créée et chargée en mémoire, mais les limites de la vue ne sont pas encore définies. C'est un bon endroit pour initialiser les objets que le contrôleur de vue va utiliser.

Appelé après le chargement de la vue. Pour les contrôleurs de vue créés dans le code, c'est après -loadView. Pour les contrôleurs de vue non archivés à partir d'une pointe, c'est après que la vue est définie.

4. viewWillAppear

Cet événement avertit viewControllerchaque fois que la vue apparaît à l'écran. Dans cette étape, la vue a des limites qui sont définies mais l'orientation n'est pas définie.

Appelé lorsque la vue est sur le point d'être rendue visible. La valeur par défaut ne fait rien.

5. viewWillLayoutSubviews

Il s'agit de la première étape du cycle de vie où les limites sont finalisées. Si vous n'utilisez pas de contraintes ou de disposition automatique, vous souhaiterez probablement mettre à jour les sous-vues ici. Ceci est uniquement disponible dans iOS> = 5.0. Donc, si vous prenez en charge iOS <5.0, ne vous attendez pas à ce qu'il apparaisse dans l'image.

Appelé juste avant l'appel de la méthode layoutSubviews du contrôleur de vue. Les sous-classes peuvent être implémentées si nécessaire. La valeur par défaut est un nop.

6. viewDidLayoutSubviews

Cet événement informe le contrôleur de vue que les sous-vues ont été configurées. C'est un bon endroit pour apporter des modifications aux sous-vues une fois qu'elles ont été définies. Ceci est uniquement disponible dans iOS> = 5.0. Donc, si vous prenez en charge iOS <5.0, ne vous attendez pas à ce qu'il apparaisse dans l'image.

Appelé juste après l'appel de la méthode layoutSubviews du contrôleur de vue. Les sous-classes peuvent être implémentées si nécessaire. La valeur par défaut est un nop.

7. viewDidAppear

L' viewDidAppearévénement se déclenche après la présentation de la vue à l'écran. Ce qui en fait un bon endroit pour obtenir des données d'un service backend ou d'une base de données.

Appelé lorsque la vue a été entièrement transférée sur l'écran. La valeur par défaut ne fait rien

8. viewWillDisappear

L' viewWillDisappearévénement se déclenche lorsque la vue présentée viewControllerest sur le point de disparaître, de disparaître, de se couvrir ou de se cacher derrière l'autre viewController. C'est un bon endroit où vous pouvez restreindre vos appels réseau, invalider le minuteur ou libérer des objets qui y sont liés viewController.

Appelé lorsque la vue est rejetée, couverte ou autrement masquée.

9. viewDidDisappear

Il s'agit de la dernière étape du cycle de vie à laquelle tout le monde peut s'attaquer, car cet événement se déclenche juste après que la vue présentée viewControllera disparu, rejetée, couverte ou masquée.

Appelé après que la vue a été rejetée, couverte ou autrement cachée. La valeur par défaut ne fait rien

Maintenant, selon Apple, lorsque vous implémentez ces méthodes, vous devez vous rappeler d'appeler l' superimplémentation de cette méthode spécifique.

Si vous sous-classe UIViewController, vous devez appeler la super implémentation de cette méthode, même si vous n'utilisez pas de NIB. (Par commodité, la méthode init par défaut le fera pour vous et spécifiera nil pour les deux arguments de cette méthode.) Dans la NIB spécifiée, le proxy du propriétaire du fichier devrait avoir sa classe définie dans votre sous-classe de contrôleur de vue, avec la sortie de vue connecté à la vue principale. Si vous appelez cette méthode avec un nom de nib nul, la -loadViewméthode de cette classe tentera de charger une NIB dont le nom est le même que la classe de votre contrôleur de vue. Si une telle NIB n'existe pas, vous devez alors appeler -setView:avant que -viewsoit invoqué, ou remplacer la -loadViewméthode pour configurer vos vues par programme.

J'espère que cela vous a aidé. Merci.

MISE À JOUR - Comme @ThomasW l'a souligné à l'intérieur du commentaire viewWillLayoutSubviewset viewDidLayoutSubviewssera également appelé à d'autres moments lorsque des sous-vues de la vue principale sont chargées, par exemple lorsque des cellules d'une vue de table ou d'une vue de collection sont chargées.

MISE À JOUR - Comme @Maria l'a souligné dans le commentaire, la description de a loadViewété mise à jour

en complément
la source
6
viewWillLayoutSubviewset viewDidLayoutSubviewssera également appelée à d'autres moments lorsque des sous-vues de la vue principale sont chargées, par exemple lorsque des cellules d'une vue de table ou d'une vue de collection sont chargées.
ThomasW
Il y a un léger mensonge dans cette réponse: loadView () est toujours appelé, il ne devrait tout simplement pas être remplacé lors de la visualisation du contrôleur créé dans IB.
Maria
@Maria Allez-y et modifiez la réponse si vous pensez qu'elle peut être améliorée. Merci.
onCompletion
La valeur par défaut ne fait rien de mal viewWillAppear viewDidAppear viewDidDisappear. Vous devez appeler super à un moment donné.
Mick
47

iOS 10,11 (Swift 3.1, Swift 4.0)

Selon UIViewControllerdans les UIKitdéveloppeurs,

1. loadView ()

C'est là que les sous-classes doivent créer leur hiérarchie de vue personnalisée si elles n'utilisent pas de plume . Ne devrait jamais être appelé directement.

2. loadViewIfNeeded ()

Charge la vue du contrôleur de vue si elle n'a pas déjà été définie.

3. viewDidLoad ()

Appelé après le chargement de la vue. Pour les contrôleurs de vue créés dans le code, c'est après -loadView. Pour les contrôleurs de vue non archivés à partir d'une pointe, c'est après que la vue est définie.

4. viewWillAppear (_ animé: Bool)

Appelé lorsque la vue est sur le point d'être rendue visible. La valeur par défaut ne fait rien

5. viewWillLayoutSubviews ()

Appelé juste avant l'appel de la méthode layoutSubviews du contrôleur de vue. Les sous-classes peuvent être implémentées si nécessaire. La valeur par défaut ne fait rien.

6. viewDidLayoutSubviews ()

Appelé juste après l'appel de la méthode layoutSubviews du contrôleur de vue. Les sous-classes peuvent être implémentées si nécessaire. La valeur par défaut ne fait rien.

7. viewDidAppear (_ animé: Bool)

Appelé lorsque la vue a été entièrement transférée sur l'écran. La valeur par défaut ne fait rien

8. viewWillDisappear (_ animé: Bool)

Appelé lorsque la vue est rejetée, couverte ou autrement masquée. La valeur par défaut ne fait rien

9. viewDidDisappear (_ animé: Bool )

Appelé après que la vue a été rejetée, couverte ou autrement cachée. La valeur par défaut ne fait rien

10. viewWillTransition (à la taille: CGSize, avec le coordinateur: UIViewControllerTransitionCoordinator)

Appelé lorsque la vue est en transition.

11. willMove (au parent de ParentViewController: UIViewController?)

12. didMove (au parent de ParentViewController: UIViewController?)

Ces deux méthodes sont publiques pour les sous-classes de conteneurs à appeler lors de la transition entre les contrôleurs enfants. S'ils sont remplacés, les remplacements doivent garantir d'appeler le super.

L'argument parent dans ces deux méthodes est nul lorsqu'un enfant est retiré de son parent; sinon, il est égal au nouveau contrôleur de vue parent.

13. didReceiveMemoryWarning ()

Appelé lorsque l'application parent reçoit un avertissement de mémoire. Sur iOS 6.0, il ne supprimera plus la vue par défaut.

Rajamohan S
la source
2
Il est vraiment très clair que stackoverflow ne purgera pas toutes les réponses erronées et incomplètes de tout ce fil. Votre réponse semble complète en ce qui concerne les appels de méthode, donc je vais supposer que la vôtre est correcte et travailler avec cela.
Logicsaurus Rex
Qu'est-ce qu'un nibtel que mentionné ci-dessous loadView?
Petrus Theron
2
@LogicsaurusRex Je suis d'accord. De la même manière que SO marque les questions en double ou protégées, je pense qu'il devrait être capable de marquer les réponses comme obsolètes ou obsolètes
rmp251
Le point 5 ci-dessus est faux. viewWillLayoutSubviews()est appelé avant que l'objet de vue du ViewController n'invoque sa layoutSubviews()méthode
williamukoh
28

À partir d'iOS 6 et versions ultérieures. Le nouveau diagramme est le suivant:

entrez la description de l'image ici

Saad
la source
1
Appelez cette vue "A". Considérons une deuxième vue "B" qui apparaît tandis que "A" disparaît. "B.viewWillAppear" est-il avant ou après "A.viewDidDisappear"? Et y a-t-il des situations où l'ordre de ces deux changements?
ToolmakerSteve
On dirait que la nouvelle vue (B) willApear sera appelée avant la disparition. Pour la deuxième question. Besoin d'un peu de temps pour l'examiner.
Saad
21

Concentrons-nous sur les méthodes, responsables du cycle de vie de UIViewController :

  • Création:

    - (void)init

    - (void)initWithNibName:

  • Création de vue:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

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

  • Gestion du changement d'état de la vue:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload

  • Gestion des avertissements de mémoire:

    - (void)didReceiveMemoryWarning

  • Désallocation

    - (void)viewDidUnload

    - (void)dealloc

Diagramme du cycle de vie d'UIViewController

Pour plus d'informations, consultez la référence de classe UIViewController .

Alexey Pelekh
la source
19

Les méthodes viewWillLayoutSubviewset viewDidLayoutSubviewsne sont pas mentionnées dans les diagrammes, mais elles sont appelées entre viewWillAppearet viewDidAppear. Ils peuvent être appelés plusieurs fois.

gjgjgj
la source
Ils seront également appelés à d'autres moments lorsque des sous-vues de la vue principale sont chargées, par exemple lorsque des cellules d'une vue de table ou d'une vue de collection sont chargées.
ThomasW
16

La réponse de Haider est correcte pour la version antérieure à iOS 6. Cependant, depuis iOS 6, viewDidUnload et viewWillUnload ne sont jamais appelés. Les documents indiquent: "Les vues ne sont plus purgées dans des conditions de faible mémoire et cette méthode n'est donc jamais appelée."

Matt Becker
la source
J'ai essayé de mettre un point d'arrêt dans ViewWillDisappear, ViewDidDisappear, Dispose. Mais aucun d'eux n'était invoqué lorsque j'ai navigué avec la méthode PresentViewController (). Quelle pourrait être la raison ?
Sreeraj
1
Le lien ne fonctionne pas ... Alors, que fait l'OS en cas de mémoire insuffisante?
Fils du
Les enregistre sur le disque?
Ian Warburton
16

Il y a beaucoup d'informations obsolètes et incomplètes ici. Pour iOS 6 et versions ultérieures uniquement:

  1. loadView[une]
  2. viewDidLoad[une]
  3. viewWillAppear
  4. viewWillLayoutSubviews est la première fois que les limites sont finalisées
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[b]
  8. * viewDidLayoutSubviews[b]

Notes de bas de page:

(a) - Si vous supprimez manuellement votre vue pendant didReceiveMemoryWarning, loadViewet viewDidLoadsera rappelé. C'est-à-dire par défaut loadViewet viewDidLoadn'est appelé qu'une seule fois par instance de contrôleur de vue.

(b) Peut être appelé 0 fois ou plus.

bobics
la source
1
viewWillLayoutSubviewset viewDidLayoutSubviewssera également appelée à d'autres moments lorsque des sous-vues de la vue principale sont chargées, par exemple lorsque des cellules d'une vue de table ou d'une vue de collection sont chargées.
ThomasW
11

Expliquer les transitions d'états dans le document officiel: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

Cette image montre les transitions d'état valides entre les différentes méthodes de rappel «volonté» et «did»

Transitions d'état valides:


Tiré de: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Art/UIViewController Class Reference_2x.png

Luismi
la source
0

Selon le document d'Apple - Commencer à développer des applications iOS (Swift) - Travailler avec les contrôleurs de vue - Comprendre le cycle de vie du contrôleur de vue

viewDidLoad(): Appelé lorsque la vue de contenu du contrôleur de vue (le haut de sa hiérarchie de vues) est créée et chargée à partir d'un storyboard. … Utilisez cette méthode pour effectuer toute configuration supplémentaire requise par votre contrôleur de vue.

viewWillAppear(): Appelé juste avant l'ajout de la vue de contenu du contrôleur de vue à la hiérarchie des vues de l'application. Utilisez cette méthode pour déclencher toutes les opérations qui doivent se produire avant que la vue de contenu ne soit présentée à l'écran

viewDidAppear(): Appelé juste après l'ajout de la vue de contenu du contrôleur de vue à la hiérarchie des vues de l'application. Utilisez cette méthode pour déclencher toutes les opérations qui doivent se produire dès que la vue est présentée à l'écran, telles que la récupération de données ou l'affichage d'une animation.

viewWillDisappear(): Appelé juste avant la suppression de la vue du contenu du contrôleur de vue de la hiérarchie des vues de l'application. Utilisez cette méthode pour effectuer des tâches de nettoyage, comme valider des modifications ou démissionner du statut de premier répondant.

viewDidDisappear(): Appelé juste après la suppression de la vue du contenu du contrôleur de vue de la hiérarchie des vues de l'application. Utilisez cette méthode pour effectuer des activités de démontage supplémentaires.

Fred
la source