• 30 hours
  • Easy

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

Comprenez les optionnels

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

Chose promise, chose due ! Je vais vous raconter la fabuleuse histoire des optionnels ! Et nous allons pouvoir modifier notre programme grâce à eux.

Une histoire de licornes…

Il était une fois un dictionnaire. (Toutes les bonnes histoires commencent par il était une fois, non ?). Ce dictionnaire contenait le nombre de licornes se trouvant dans chaque pays comme ceci :

var nombreDeLicornes = ["France": 165, "USA": 38, "Italie": 102]

Très heureux de sa mission, notre dictionnaire coulait des jours heureux. Dans son travail, les programmes lui demandaient toujours des informations qu’il pouvait donner. Par exemple, on lui disait, donne-moi le nombre de licornes en France. Et avec plaisir, notre ami dictionnaire s’exécutait.

nombreDeLicornes["France"] // Il renvoyait 165

Mais un jour, un vicieux programme le piégea : « Donne-moi le nombre de licornes au Groenland ». 

Notre dictionnaire pris de panique par cette demande tenta l’impossible avec cette instruction :

nombreDeLicornes["Groenland"]

Mais bien sûr cette commande ne retourna rien et le programme planta. 

Personne ne se maria ni n’eut beaucoup d’enfants.

THE END

Bon OK, c’était une histoire tragique… Mais dans la vie d’un programmeur, tout n’est pas rose. Autant vous y faire tout de suite !

C’est après avoir été traumatisé pendant 50 ans par cette histoire que les créateurs de Swift ont fini par inventer les optionnels ! Vous pouvez déjà les remercier.

Parce qu’en fait, cette histoire ne se limite pas aux dictionnaires. Par exemple, je suis sûr que vous vous êtes déjà inscrit sur de nombreux sites web qui demandaient à ce que vous remplissiez un paquet d’informations. Parmi celles-ci, il y en avait qui étaient obligatoires comme votre email ou votre mot de passe. Mais souvent on vous propose d’en remplir d’autres facultatives comme votre adresse ou votre téléphone. Et si vous êtes comme moi, vous ne les remplissez pas.

Le problème c’est qu’un programmeur innocent comptait peut-être sur vous pour remplir votre numéro de téléphone pour pouvoir l’afficher sur l’application our pour vous envoyer un SMS. Et donc quelque part dans son programme il a une variable  téléphone  qui ne contient aucune valeur !  

var telephone = // Rien !

Et si jamais il essaye d’utiliser cette variable sans valeur (ou autrement dit cette variable non initialisée), son programme va planter comme vous le savez. 

D’où les optionnels !

Les optionnels, concrètement ! 

MAIS C’EST QUOI ??? 

OK j’ai peut-être fait un peu durer le suspens… En fait, un optionnel c’est un type un peu spécial. C’est le seul type qui autorise une variable à être utilisée sans valeur. Vous vous souvenez du cycle de vie d’une variable : 

  1. La variable est déclarée. À ce moment, elle a un nom et un type et on sait si elle est constante ou non. Comme la variable n’a pas de valeur à ce moment-là. Elle ne peut pas être utilisée.

  2. La variable est initialisée. Elle a une valeur. La variable peut être utilisée.

On ne peut donc pas utiliser une variable qui n’a pas été initialisée. Mais avec les optionnels si ! Car ils autorisent une variable à ne pas avoir de valeur.

On va voir tout de suite à quoi ça ressemble. Pour déclarer un optionnel, on utilise le point d’interrogation  ?  à la suite du type. Comme ceci :

var jeSuisOptionnel: Int?     // Ceci est un optionnel
var jeNeSuisPasOptionnel: Int  // Ceci est un entier

Les deux variables ci-dessus ne sont pas initialisées. Elles n’ont pas de valeur. Essayons de les utiliser : 

var jeSuisOptionnel: Int?      // Ceci est un optionnel
jeSuisOptionnel                // Le Playground affiche nil
var jeNeSuisPasOptionnel: Int  // Ceci est un entier
jeNeSuisPasOptionnel           // Le Playground plante…

Pour la variable classique, le programme plante, car on essaye d’accéder à la valeur d’une variable qui n’en a pas ! C’est interdit par Swift. Mais c’est autorisé pour les optionnels. Et donc pour la variable  jeSuisOptionnel , le programme renvoie  nil . 

nil ?

 nil  en Swift, c’est un mot clé qui veut dire nada / rien / quedal / zip / pas de valeur. Et c’est bien le cas, notre variable  jeSuisOptionnel  ne contient rien.  

Et à quoi ressemble un optionnel qui a une valeur ? Essayons !

var jeSuisOptionnel: Int? = 12
print(jeSuisOptionnel)

Dans la console vous devriez voir :

Optional(12)

Il y a bien écrit  Optional(12)  et pas  12  !

Pourquoi ?

Pour une raison très simple, mais cruciale pour que vous compreniez correctement les optionnels.

La variable  jeSuisOptionnel  N’EST PAS DU TYPE  Int  MAIS DU TYPE  Optional . Je répète : La variable  jeSuisOptionnel  N’EST PAS DU TYPE  Int  MAIS DU TYPE  Optional 

Pour être sûr que le message soit bien passé, je vais vous faire un petit cadeau.

Un optionnel, c’est un paquet cadeau.

Eh oui, un optionnel c’est comme un paquet cadeau qui englobe une valeur. Si on vous offre un paquet cadeau, vous ne savez pas ce qu’il y a dedans avant de l’ouvrir. Plus précisément, à l’intérieur :

  • Soit il n’y a rien. Quelqu’un vous a fait une mauvaise blague…

  • Soit il y a quelque chose mais vous ne savez pas quoi avant de l’ouvrir. Joyeux anniversaire !

 Un optionnel se comporte exactement comme l’explique le schéma suivant.

Dans le schéma précédent,  x  est un optionnel et non un String ! Le type  String?  ne doit pas se lire : « Je suis peut-être un String » mais « Je suis un optionnel qui contient peut-être un String ». 

Déballer le cadeau

Les optionnels sont bien pratiques pour gérer des variables qui peuvent ne pas avoir de valeur. Mais alors comment accède-t-on à sa valeur ? Il existe 3 méthodes :

  • 1 méthode rapide

  • 2 méthodes sécurisées 

La méthode rapide

Pour déballer un optionnel, on peut utiliser le point d’exclamation  !  à la fin de la variable comme ceci :

var jeSuisOptionnel: Int? = 12
jeSuisOptionnel! // La variable est déballée avec le point d’exclamation

Si on essaye d’écrire print(jeSuisOptionnel!), la console affichera directement 12 et non Optional(12). L’optionnel a été déballé. C’est comme si on utilisait directement une variable non optionnelle. Le problème, c’est que du coup si l’optionnel n’a pas de valeur, le programme va planter.

var jeSuisVide: Int?
jeSuisVide! // Le programme plante car la valeur est nil

Cette méthode est dangereuse, car pour utiliser le point d’exclamation, il faut être certain que la variable ait une valeur.

La méthode sécurisée 1

Pour pallier à ce risque, il existe deux moyens pour s’assurer que la variable a une valeur. Le premier est assez intuitif :

if jeSuisUnOptionnel != nil {
    print("La variable contient une valeur")
}

Ici, on vérifie que l’optionnel ne vaut pas nil. Si c’est le cas, on peut donc le déballer sans risque avec le point d'exclamation : 

if jeSuisUnOptionnel != nil {
    print("La variable vaut \(jeSuisUnOptionnel!)")
}

La méthode sécurisée 2

La deuxième méthode est plus subtile, mais aussi plus pratique ! C’est la raison pour laquelle c’est aussi la plus utilisée ! Elle s’utilise comme ceci : 

if let variableDéballée = variableOptionnelle {
    print("La variable déballée vaut \(variableDéballée)")
}

Je vais détailler ce qu’il se passe ici : 

  1. Le programme regarde si la variable  variableOptionnelle  vaut  nil .

  2. Si elle ne contient pas nil, le programme crée une variable constante nommée :  variableDéballée .

  3. La valeur de la variable déballée est attribuée à la nouvelle constante  variableDéballée .

L’avantage de cette méthode, c’est que la variable nouvellement créée n’est pas de type optionnel. C’est une variable classique qu’on peut donc utiliser normalement. On appelle cela une déclaration optionnelle (ou optional binding en anglais). C’est très courant en Swift.

Un jour vous repenserez à ce jour où vous n’utilisiez pas if let et vous aurez un sourire nostalgique (éventuellement en pensant à votre prof !). ;)

Utilisation 

Cela fait donc trois méthodes ! Alors, comment décider quelle méthode utiliser ? Suivez le guide ! 

Quelques usages des optionnels

Les optionnels au début, ça peut être un peu déstabilisant. Voilà donc quelques exemples d’utilisation des optionnels pour que vous sentiez leur intérêt. 

La conversion de String en Int 

On a vu que l’on pouvait transformer un type en un autre en utilisant l’initialisation du type. Par exemple, comme ceci :

Int(3.4) // Renvoie 3

On a converti 3.4 de type double en 3 qui est de type Int grâce à l’instruction Int. Avec cette méthode on peut aussi convertir un type  String  en type  Int . Comme ceci :

var a = Int("123")

Et si l’on écrit  print(a) , la console affiche  Optional(123) . Eh oui !  a  est un optionnel ! Pourquoi ? Car pour transformer un  String  en  Int , il faut que ce String contienne uniquement des chiffres. Par exemple si j’écris : 

var a = Int("Des pommes")

L’initialisation ne va pas fonctionner, car on ne peut pas convertir la chaîne  "Des pommes" en entier et  a  va valoir  nil . Donc cette instruction permettant de créer un  Int  à partir d’un  String  renvoie :

  • Soit un entier si le String utilisé est convertible

  • Soit nil si le String n’est pas convertible en Int 

Et c’est bien la définition d’un optionnel ! 

Les propriétés first et last

 Pour rappel, pour accéder aux données d’un tableau, on utilise son index. Par exemple :

var poupeesRusses = ["petite", "moyenne", "grande"]
poupeesRusses[1] // Moyenne

Pour accéder à la première valeur de ce tableau, on ferait :  poupeesRusses[0]  et la dernière valeur on peut faire  poupeesRusses[2] . Çà vous le savez. Mais sachez que Swift propose des propriétés bien pratiques pour ces deux cas : les propriétés  first  et  last  :

var petite = poupeesRusses.first
var grande = poupeesRusses.last

Cela permet d’avoir un programme qui se lit plus clairement. Et c’est plus pratique.

Seulement, si le tableau est vide, les propriétés  first  et  last  ne peuvent rien renvoyer. Donc elle renvoie nil. Du coup les propriétés  first  et  last  peuvent renvoyer :

  • soit un élément du tableau

  • soit nil si le tableau est vide 

C’est donc un optionnel. Vous pouvez le tester en écrivant  print(grande)  qui affiche  Optional("grande") .  

Les dictionnaires

Pour accéder à une valeur dans un dictionnaire, on utilise sa clé comme ceci :

var barn = ["milk": 0, "wheat": 0, "wool": 0]
barn["milk"] // Renvoie 0

Çà vous le savez. Mais je vous ai menti. Et l’heure de vérité est arrivée ! En utilisant la clé, le dictionnaire ne renvoie pas directement la valeur mais un optionnel. Essayez d’écrire par exemple :

print(barn["milk"])

La console affiche  Optional(0) . Pourquoi ne pas renvoyer la valeur directement me direz vous ? Car si l’on se trompe de clé, le dictionnaire ne peut rien renvoyer (cf la fameuse histoire de licornes…). Par exemple, si j’écris :

print(barn["MILK"])

Le dictionnaire ne contient aucune valeur associée à la clé  MILK . Et donc il va renvoyer  nil . Autrement dit, lorsque je cherche à accéder à un élément dans un dictionnaire, le dictionnaire renvoie :

  • Une valeur si la clé existe

  • Rien si la clé n’existe pas

Donc il est normal que le dictionnaire renvoie un optionnel ! Donc pour effectivement accéder à sa valeur, il faut le déballer.

Implémentation

Avec ces connaissances, je vous laisse terminer l’implémentation de notre programme en utilisant le dictionnaire suivant : 

var barn = ["milk": 0, "wheat": 0, "wool": 0]

À vous de jouer ! Essayez sans regarder la solution !








































// Le prix du voyage
let price = 1499.0

// L'argent de Joe
var money = 0.0

// Le nombre de jours pendant lesquels Joe doit économiser
var numberOfDay = 0

// La grange de Joe : [lait, blé, laine]
var barn = ["milk": 0, "wheat": 0, "wool": 0]

while money < price {
    // Joe nourrit les vaches tous les jours
    money -= 4

    // On calcule la taille de la grange
    var barnSize = 0
    for (goods, count) in barn {
        barnSize += count
    }

    if barnSize >= 500 {
        // On vends !
        money += Double(barn["milk"]!) * 0.50
        money += Double(barn["wheat"]!) * 0.30
        money += Double(barn["wool"]!) * 1

        // On vide la grange
        barn = ["milk": 0, "wheat": 0, "wool": 0]
    } else {
        // C'est une journée normale

        if numberOfDay % 30 == 1 {
            // Joe moissonne
            barn["wheat"]! += 100
        } else if numberOfDay % 30 == 10 || numberOfDay % 30 == 20 {
            // Joe tond les moutons
            barn["wool"]! += 30
        } else {
            // Joe trait les vaches
            barn["milk"]! += 30
        }
    }

    // On passe au jour suivant
    numberOfDay += 1
}


print("Il aura fallu \(numberOfDay) jours à Joe pour économiser \(money) €")

Ici, j’utilise la méthode rapide avec le point d’exclamation pour déballer les valeurs de mon dictionnaire, car je suis absolument certain que les clés que j’utilise correspondent à des valeurs, car je les ai créées quelques lignes plus haut.

En résumé

  • Un optionnel est un type qui permet à une variable d’être utilisée sans valeur.

  • Dans le cas où l’optionnel ne contient pas de valeur, on dit que sa valeur est  nil .

  • Il faut se représenter un optionnel comme un paquet cadeau qui contient soit :

    • Une valeur du type indiqué

    • Rien

  • Soit la déclaration suivante :

    var i: Int?

     i  n’est pas du type entier mais du type optionnel. Mais si  i  contient une valeur, ce sera un entier.

  • Un optionnel doit donc être déballé, selon trois méthodes :

    • Une méthode rapide avec ! mais qui fera planter le programme si la variable ne contient pas de valeur.

      optionnel!
    • Une méthode sécurisée qui permet seulement de vérifier si la variable contient une valeur ou non.

      if optionnel != nil { 
          // optionnel contient à coup sur une valeur mais n'est pas encore déballé
      }
    • Une méthode sécurisée qui permet d’accéder à la variable par la création d’une nouvelle variable.

      if let déballé = optionnel {
          // J’utilise déballé normalement ici
      }
  • Lorsqu’on accède aux valeurs d’un dictionnaire avec une clé, le dictionnaire renvoie un optionnel et non la valeur directement.

Example of certificate of achievement
Example of certificate of achievement