Nous avons maintenant des classes qui contiennent des propriétés. Nos classes permettent donc de stocker de l'information. Mais je ne suis pas tout à fait satisfait de nos propriétés pour l'instant.
Pourquoi ?
Eh bien, car elles ont toutes des valeurs par défaut, et parfois ça n'a pas vraiment de sens. Prenons par exemple la propriété driverName
. Ce n'est pas logique que le nom du chauffeur soit par défaut Joe, il n'y a aucune statistique à ma connaissance qui le justifie...
Gérez des propriétés non initialisées
Essayons donc de supprimer la valeur par défaut. Pour cela, je vais donc remplacer la déclaration de la propriété en supprimant l'initialisation de celle-ci :
var driverName: String
À ce moment-là, on a une erreur qui dit :
Qu'est-ce que ça veut dire ? Pour bien comprendre, imaginons que l'on va créer une instance de la classe Bus. Lorsque l'on fait ça, le programme va regarder toutes les propriétés de la classe Bus et créer autant de variables correspondantes. Toutes ces variables vont être mises dans un petit paquet, et on a notre instance !
Mais lorsque l'on crée une instance, on crée autant de variables qu'il y a de propriétés. Et toutes ces variables doivent être prêtes à l'emploi. Pas de souci pour celles qui ont des valeurs par défaut. Mais quand le programme va vouloir créer la variable driverName
, il ne saura pas quelle valeur lui attribuer.
Pas grave, il n'y a qu'à ne pas lui mettre de valeur !
C'est filou ! Mais quel est le type de notre variable ?
String...
En effet, cette variable n'est pas optionnelle, alors on ne peut pas l'utiliser sans valeur. Le programme va planter.
OK... Mais quel rapport avec l'erreur affichée ?
Le rapport, c'est que pour résoudre ce problème, nous avons 2 solutions :
soit je déclare ma variable
driverName
optionnelle, et tout ira bien :var driverName: String?
. La variable a le droit maintenant de ne pas avoir de valeur. À priori, ça vous connaissez ;
soit j'utilise ce qu'on appelle un initialiseur dans lequel je vais... initialiser ma variable ! Là par contre, c'est nouveau ! Alors, laissez-moi vous montrer !
Initialisez une classe
Tout d'abord, qu'est-ce qu'un initialiseur ? C'est une fonction qui va être appelée au moment de la création d'une instance de classe, et dans laquelle on peut faire quelques calculs pour initialiser nos propriétés. On crée cette fonction à l'intérieur de la classe en utilisant le mot clé init
:
init() {
// Ici on peut initialiser nos propriétés
}
Par exemple, dans le cas de notre classe Bus
, on va pouvoir écrire :
init() {
driverName = "Joe"
}
Et voilà ! Nous n'avons plus d'erreur ! Vous pouvez tester en créant une instance, la propriété driverName
aura pour valeur Joe.
Oui enfin, il n'y a pas de quoi sauter au plafond...
Bah pourquoi ?
On n’a fait que déplacer le problème. La propriété driverName
a toujours une valeur par défaut...
Hmm... Bien vu ! Mais vous ne m'aurez pas aussi facilement !
Initialisez une classe avec des paramètres
Je vous ai dit que l'initialiseur, c'était une fonction. Eh bien comme toute fonction, elle peut avoir des paramètres ! On peut par exemple écrire :
init(name: String) {
driverName = name
}
Et maintenant, pour instancier un bus, on va écrire :
var bus = Bus(name: "Martine")
L'initialisation du bus a changé ! Maintenant Swift exige que nous passions des paramètres pour instancier un nouveau bus. Et de cette façon, on peut choisir, pour chaque nouvelle instance du bus, le nom du chauffeur. Alors, heureux ?
Utilisez le mot-clé self
Notre initialisation a désormais un paramètre qui s'appelle name
. C'est bien, mais ce n'est pas parfait. Pour que l'initialisation soit claire, en général, on préfère donner comme nom de paramètre le nom exact de la propriété, soit ici driverName
. Alors, modifions ça :
init(driverName: String) {
driverName = driverName
}
Patatras ! Nous avons une erreur. L'erreur vient du fait que nous avons deux fois driverName
, et que l'ordinateur, donc, ne sait plus si on parle de la propriété ou du paramètre. Heureusement, nous avons le vaillant mot-clé self
à notre secours !
Euh... quoi ?
Le mot-clé self
permet dans une classe de faire référence à elle-même. Le plus simple, c'est que je vous montre :
init(driverName: String) {
self.driverName = driverName
}
self
se comporte comme une instance de la classe dans laquelle il est écrit. Donc quand j'écris self.driverName
à l'intérieur de la classe Bus
, je fais référence à la propriété driverName
de la classe Bus
.
En écrivant ceci, Swift sait maintenant que self.driverName
, c'est la propriété, et driverName
après le =
, c'est le paramètre.
Voilà, nous avons désormais un initialiseur bien pratique pour notre classe Bus !
Désinitialisez notre classe
Maintenant que l’on sait comment initialiser notre classe, il faut que je vous parle de sa désinitialisation. Comme son nom l’indique, la désinitialisation, c’est l’inverse de l’initialisation. C’est-à-dire qu’au lieu de créer une instance, nous la détruisons.
Concrètement, lorsque j’initialise une instance, mon ordinateur garde une place en mémoire pour celle-ci. C’est pour cela que je peux la réutiliser. Mais je n’ai pas d'espace infini sur ma machine, il faut donc supprimer ce dont je n’ai plus besoin pour pouvoir recréer de nouvelles instances. C’est ce que fait la méthode deinit
.
Vous avez de la chance, cette méthode est appelée automatiquement par Swift dès que vous ne vous servez plus d’une variable. Ce n’est pas le cas dans tous les langages.
La plupart du temps, vous n’aurez pas à vous en préoccuper, mais je vais vous montrer un exemple d’utilisation :
Exemple terminus, tout le monde descend !
var numberOfStudentsAtSchool = 0
class Bus {
var driverName: String
var seats = 20
var occupiedSeats = 0
let numberOfWheel = 4
init(driverName: String) {
self.driverName = driverName
}
deinit {
numberOfStudentsAtSchool -= occupiedSeats
}
}
bus.occupiedSeats += 1
bus.occupiedSeats += 1
Concrètement ici, nous cherchons à connaître le nombre d’enfants qui sont arrivés à l'école. On pourrait avoir plusieurs bus pour les y emmener, donc plusieurs instances de notre classe Bus
. C’est pour cela que numberOfStudentsAtSchool
n’appartient pas à notre classe Bus
.
Lorsque le bus a fini sa tournée, on transfère au nombre d’élèves arrivés ceux qui sont dans notre bus et qui vont descendre. Nous pouvons donc nous servir de la méthode deinit
pour faire cette action automatiquement, dès que nous n’avons plus besoin de notre instance bus
. deinit
ne prend pas de paramètres.
À vous de jouer !
Comme je suis généreux, je vous propose non pas 1, ni 2, mais bien 3 exercices ! Woooohouuu !
Exercice 1
Ajoutez un initialiseur à la classe RoadSection
. Cette classe est vide pour le moment, ajoutez-lui un initialiseur qui va appeler la fonction canvas.createRoadSection()
de sorte qu'à chaque fois qu'on crée une nouvelle instance de RoadSection
, une section de route est ajoutée sur le canevas.
Exercice 2
Ajoutez un initialiseur la classe Road
qui prend pour paramètre length
, qui est un entier et qui détermine la taille de la route. Cet initialiseur permet de remplir le tableau des sections de route d'autant de sections qu'indiqué par le paramètre length
.
Exercice 3
Ajoutez un initialiseur à la classe Student
.
Le contenu de l’exercice se trouve dans le dossier Github P2C3.
Ouvrez un nouveau Playground Xcode.
Copiez le contenu du fichier “main.swift” dans votre Playground.
Suivez les instructions.
En résumé
Pour utiliser des propriétés sans valeur par défaut, on peut :
leur donner un type optionnel : la propriété pourra ne pas avoir de valeur ;
utiliser un initialiseur.
Un initialiseur est une fonction qui est appelée lors de la création d'une instance. Pour créer un initialiseur, on utilise le mot-clé
init
. Comme toute fonction, un initialiseur peut avoir des paramètres.Le mot-clé
self
fait référence à la classe dans laquelle il est appelé. Il s'utilise comme une instance de la classe.La désinitialisation est indispensable après une initialisation, mais heureusement Swift le fait automatiquement pour vous.
Ça y est, vous maîtrisez l’initialisation et la désinitialisation de vos classes ! Rendez-vous au prochain chapitre pour découvrir comment leur ajouter des méthodes.