• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/26/20

Analysez le cycle de vie du contrôleur

Log in or subscribe for free to enjoy all this course has to offer!

Voilà un petit bout de temps que vous utilisez les contrôleurs et vous avez certainement croisé des méthodes comme :

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}

Et à moins d'avoir déjà été suffisamment curieux pour chercher par vous-même, vous ne savez sans doute pas précisément ce qu'il se passe dans cette méthode. Dans ce chapitre, nous allons lever un voile sur tout ça en parlant du cycle de vie du contrôleur.

Certes, mais ne paniquez pas ! Ça va vous servir à peu près tous les jours dans votre vie de développeur iOS, donc ça vaut le coup ! Et puis, ça ne vous fera pas de mal, je vous trouve un peu trop heureux là...

De quoi ça va causer ?

Non, on ne va pas parler de biologie ! Le cycle de vie du contrôleur décrit les étapes par lesquelles passe le contrôleur entre la demande d'affichage d'une nouvelle page et sa disparition de l'écran.

Autrement dit, le cycle de vie, c'est l'histoire de la naissance, la vie et la mort d'un contrôleur.

La naissance

Un contrôleur passe par de nombreuses étapes avant que la vue ne soit affichée à l'écran. Comprendre ces étapes va vous permettre de les utiliser pour effectuer certaines préparations ou actions sur ce dernier.

Initialisation

La première étape, comme pour n'importe quel objet, c'est l'initialisation du contrôleur. L'objet contrôleur est créé en mémoire avec toutes ses propriétés. Comme toute initialisation, cela se fait à l'occasion de la méthode init :

init?(coder aDecoder: NSCoder)

À cette étape, on a juste instancié un objet. Il n'est pas question de la vue. C'est comme lorsque vous écrivez ceci :

var monObjet = Objet()

Chargement de la vue

L'étape suivante, c'est le chargement de la vue. À cette étape, on crée en mémoire la propriété view du contrôleur, la vue principale (rappel sur cette notion ici). On va y ajouter toutes les sous-vues. On va pouvoir les placer, les modifier, etc. À cette étape, on prépare toutes les propriétés de la vue et de ses sous-vues. Mais on ne les affiche pas à l'écran.

Cela a lieu dans cette méthode :

func loadView()

Vous pouvez faire l'override de cette méthode si vous souhaitez créer vos vues dans le code. Mais si vous utilisez le storyboard, c'est fait automatiquement pour vous et vous pouvez ignorer cette étape.

Une fois cette étape terminée, la fameuse fonction viewDidLoad est appelée :

func viewDidLoad()

Quand cette fonction est appelée, la vue est donc complètement chargée en mémoire, mais elle n'est pas affichée à l'écran.

Affichage de la vue à l'écran

Le contrôleur est prêt, la vue est prête. On va pouvoir l'afficher à l'écran de l'iPhone.

Cette étape s'accompagne de deux méthodes :

func viewWillAppear(_ animated: Bool)
func viewDidAppear(_ animated: Bool)

La première est appelée juste avant que la vue soit affichée à l'écran. C'est le bon moment pour préparer une animation que l'on veut jouer à l'affichage de la vue.

La deuxième est appelée juste après que la vue soit affichée à l'écran. C'est le bon moment pour lancer une animation, un son ou une vidéo. La vue vient d'arriver à l'écran, l'utilisateur va pouvoir en profiter !

La vie

Ça y est ! La vue est à l'écran. L'utilisateur va interagir avec en cliquant sur des boutons, en la visualisant simplement ou en faisant des gestes sur l'écran tactile.

C'est là qu'intervient la majeure partie de votre travail en tant que développeur. Il y a simplement une petite chose à noter ici : la gestion de la mémoire.

Vous avez peut-être aperçu cette méthode :

func didReceiveMemoryWarning()

Un iPhone, contrairement à un ordinateur, c'est petit. Du coup, ses capacités sont limitées. Il ne peut retenir qu'un nombre limité d'objets en même temps dans ce qu'on appelle sa mémoire vive. Et s’il est sur le point d'atteindre sa limite, il vous prévient avant pour que vous puissiez libérer la mémoire de choses inutiles.

La mort

Eh oui, cette histoire ne se finit par très bien... :/

Disparition de l'écran

Lorsque votre vue va disparaître de l'écran, si vous passez à la vue suivante par exemple, deux méthodes vont être appelées :

func viewWillDisappear(_ animated: Bool)
func viewDidDisappear(_ animated: Bool)

Comme précédemment, la première est appelée avant la disparition de la vue à l'écran et la deuxième juste après.

Suppression du contrôleur

Si votre vue n'est plus à l'écran, cela ne signifie pas forcément la fin définitive pour votre contrôleur. Prenons un exemple pour bien comprendre ce point.

Mettons que j'ai un Navigation Controller qui gère la navigation entre deux contrôleurs A et B.

1/ A l'allumage de l'application, le contrôleur A est créé puis la vue A correspondante est chargée en mémoire et ensuite la vue A est montrée à l'écran.

2/ Ensuite, l'utilisateur navigue vers le contrôleur B. La vue A du coup disparaît de l'écran et le contrôleur B est créé puis la vue B est chargée et enfin elle apparaît à l'écran.

Notre pile de navigation ressemble à ceci :

B

A

Donc le contrôleur A existe toujours puisqu'il est stocké dans la pile de navigation. Mieux, la vue est toujours chargée ! Elle n'est juste pas montrée à l'écran.

3/ L'utilsateur revient à la vue A et la pile de navigation ressemble à ceci :

A

Non seulement la vue B a disparu de l'écran, mais cette fois le contrôleur B n'est plus stocké dans la pile de navigation. Le contrôleur B a bel et bien été supprimé de la mémoire.

La mort effective du contrôleur a donc lieu lorsqu'il quitte la pile de navigation.

viewDidLoad VS viewDidAppear

Cela a une conséquence importante pour deux méthodes que vous risquez d'utiliser souvent, viewDidLoad et viewWillAppear :

  • viewDidLoad est appelée une seule fois dans la vie du contrôleur

  • viewDidAppear est appelée plusieurs fois

Pourquoi ?

Reprenons notre exemple avec les contrôleurs A et B. Et concentrons-nous uniquement sur l'enchaînement des méthodes du cycle de la vie de A.

1/ A est appelée à l'écran, les méthodes suivantes sont exécutées :

// Le contrôleur est créé en mémoire
init?(coder aDecoder: NSCoder)
// La vue est chargée
loadView()
viewDidLoad()
// La vue apparaît à l'écran
viewWillAppear(_ animated: Bool)
viewDidAppear(_ animated: Bool)

Jusque là viewDidLoad et viewDidAppear ont toutes les deux été appelées une fois.

2/ On passe à la vue B. Sur le contrôleur A, les méthodes suivantes sont exécutées.

// La vue disparaît de l'écran
viewWillDisappear(_ animated: Bool)
viewDidDisappear(_ animated: Bool)

3/ On revient à la vue A. Les méthodes suivantes sont appelées :

// La vue revient à l'écran
viewWillAppear(_ animated: Bool)
viewDidAppear(_ animated: Bool)

Et voilà, viewDidAppear (et viewWillAppear d'ailleurs) est appelée une seconde fois, mais viewDidLoad n'a pas été appelée.

Pourquoi on ne repasse pas par viewDidLoad?

Vous connaissez déjà la réponse ! Alors, débrouillez-vous !

Si je pose la question, a priori...

Bon OK. Comme on l'a vu juste au-dessus, le contrôleur A reste stocké dans la pile de navigation quand B est à l'écran. Donc le contrôleur A continue à exister et il garde la vue chargée en mémoire pour pouvoir à tout moment la refaire passer à l'écran sans avoir à tout recharger.

Et donc si je fais dix fois l'aller-retour entre A et B, je vais passer dix fois par viewDidAppear, mais je ne repasse plus par viewDidLoad car la vue n'a pas été rechargée.

OK je vois.

Merci ;) !

Du coup, si vous voulez recharger le contenu d'une page à chaque fois qu'elle apparaît, il faudra mettre cela dans viewWillAppear plutôt que viewDidLoad. En revanche, si vous souhaitez vous placer en tant qu'observateur pour une notification par exemple, vous n'avez besoin de le faire qu'une fois, donc faites le dans viewDidLoad.

Résumé

En guise de résumé, je vous propose le schéma ci-dessous :

Ça y est ! Vous avez toutes les bases de navigation et comme tout en iOS, il y a beaucoup d’autres choses que vous pouvez aller découvrir par vous-même. Mais si la fondation est solide, le reste ira tout seul, vous n’avez plus besoin de moi !

Dans la prochaine partie, nous allons créer le formulaire d’inscription et vous allez découvrir comment utiliser les composants principaux d’un formulaire, comme les switchs, les champs de texte, les sélecteurs et d’autres.

Example of certificate of achievement
Example of certificate of achievement