• 20 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/1/19

Enrichissez vos propriétés

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

Pour le moment, vous connaissez deux types de propriétés :

  • les propriétés d'instance

  • les propriétés de classe (ou statiques)

Qu'elles soient statiques ou d'instance, toutes les propriétés que vous avez vues pour le moment sont ce qu'on appelle des propriétés stockées. Cela veut dire qu'elles sont associées à une valeur qui est stockée en mémoire.

Il existe en Swift un autre type de propriété : les propriétés calculées. Et c'est ce que nous allons voir dans ce chapitre.

Le concept des propriétés calculées

Les propriétés calculées diffèrent des propriétés stockées ainsi :

  • les propriétés stockées sont associées à une valeur

  • les propriétés calculées sont associées à un calcul

Un calcul ? C'est-à-dire ?

En fait, si on y réfléchit, une propriété admet deux actions :

  • une action pour récupérer la valeur contenue, on va appeler cette action get (récupérer en anglais)

  • une action pour modifier la valeur contenue, on va appeler cette action set (modifier en anglais)

Dans une propriété stockée, ces actions ont lieu automatiquement. Dans une propriété calculée, on va pouvoir modifier les actions get et set.

Implémentation des propriétés calculées

Rien de tel qu'un bon exemple pour voir comment tout ça fonctionne. Je vous présente la classe Carré suivante qui permet de définir un carré.

class Carré {
    var longueur = 1
}

J'aimerais bien rajouter une propriété périmètre à ma classe qui me permettrait d'obtenir le périmètre de la classe. Le périmètre d'un carré c'est 4 fois la longueur donc allons-y !

class Carré {
    var longueur = 1
    var périmètre = 4
}

Hmm... C'est bien, mais le problème, c'est que si je modifie la longueur de mon carré, mon périmètre ne sera plus exact. On voit apparaître la limite des propriétés stockées. Je vais donc vous montrer comment créer une propriété calculée. Transformons donc notre périmètre en propriété calculée :

class Carré {
    var longueur = 1

    var périmètre: Int {
        get {
            return 4
        }
        set {

        }
    }
}

Voici la forme basique d'une propriété calculée. Pour l'instant elle a exactement le même rôle qu'avant. Détaillons un peu ce qui s'y trouve :

  • Tout d'abord il faut indiquer le type de la propriété. Comme je ne lui donne plus de valeur, il faut lui préciser le type explicitement.

  • Ensuite j'ouvre des accolades un peu comme une fonction.

  • À l'intérieur des accolades se trouvent deux sortes de sous-fonctions :

    • get : c'est l'action qui permet de récupérer une valeur, on appelle ça le getter. Elle se comporte exactement comme une fonction avec une valeur de retour de type Int. Pour l'instant, elle renvoie simplement 4.

    • set : c'est l'action qui permet de modifier notre valeur, on appelle ça le setter. Pour l'instant cette fonction est vide. Telle quelle, elle ne change rien à ce qu'il se passe lorsqu'on modifie la valeur de la variable périmètre.

Commençons par modifier notre getter :

var périmètre: Int {
    get {
        return longueur * 4
    }
    set {

    }
}

De cette façon, le périmètre sera toujours égal à 4 fois la longueur :

let c = Carré()
c.longueur = 4
c.périmètre // Affiche 16

Le problème maintenant, c'est lorsqu'on modifie le périmètre :

let c = Carré()
c.périmètre = 8
c.longueur // Affiche 1

La longueur ne s'adapte pas quand le périmètre change pourtant les deux doivent toujours être reliés. Je vais donc modifier le setter pour qu'il modifie la longueur à chaque fois que le périmètre est modifié :

var périmètre: Int {
    get {
        return longueur * 4
    }
    set {
        longueur = newValue / 4
    }
}

Le setter se comporte exactement comme une fonction qui a pour paramètre newValuenewValue contient la nouvelle valeur que l'on est en train de donner au périmètre. Par exemple, si j'écris :

let c = Carré()
c.périmètre = 8

Dans ce cas, newValue vaut 8 et donc maintenant si j'affiche la longueur, j'obtiens bien 8 / 4 = 2 :

c.longueur // Affiche 2

En résumé :

  • le getter se comporte comme une fonction avec une valeur de retour du type de la propriété. Il est appelé lorsqu'on veut récupérer la valeur de la propriété.

  • le setter se comporte comme une fonction avec un paramètrenewValuedu type de la propriété. Il est appelé lorsqu'on modifie la valeur de la propriété.

Les propriétés calculées en lecture seule

Parfois nous écrivons des propriétés que nous n'avons pas besoin de modifier. Nous ne pouvons pas pourtant en faire des constantes, car leur valeur peut varier en fonction des autres valeurs. Par exemple, ajoutons une propriété description à notre Carré.

class Carré {
    let description = "Je suis un carré"
    
    // (...)
}

C'est bien, mais c'est un peu générique. Essayons d'afficher plutôt : "Je suis un carré de longueur X". Il va nous falloir une propriété calculée :

var description: String {
    get {
        return "Je suis un carré de longueur \(longueur)"
    }
    set {

    }
}

Voilà qui fonctionne comme on le souhaite. Mais on veut aller plus loin. On ne veut pas que quelqu'un puisse modifier la description, car il pourrait écrire n'importe quoi et notre description ne serait plus vrai.

On va transformer cette propriété calculée en propriété calculée en lecture seule comme ceci :

var description: String {
    get {
        return "Je suis un carré de longueur \(longueur)"
    }
}

Il suffit d'effacer le setter et cette propriété ne peux plus être modifiée ! On dit qu'elle est en lecture seule. Je ne peux donc plus écrire :

let c = Carré()
c.description = "N'importe quoi" // error: 'description' is a get-only property

Quelques règles des propriétés calculées

Maintenant que vous avez bien compris ce que sont les propriétés calculées, je vais vous annoncer quelques règles ou remarques à leur sujet.

1. Les propriétés calculées ne sont jamais constantes. Autrement dit on ne peut pas les déclarer avec let. Leur valeur est calculée donc, par définition, elle est appelée à changer.

2. Les propriétés calculées ont toujours un getter. Au minimum, une propriété, ça renvoie une valeur donc il faut toujours pouvoir le faire :

// OK il y a un getter
var propriétéCalculée: Type {
    get {
        return quelqueChose
    }
    set {

    }
}

// OK il y a un getter, la propriété est en lecture seule
var propriétéCalculée: Type {
    get {
        return quelqueChose
    }
}

// OK la propriété est en lecture seule, le getter est directement dans les accolades
var propriétéCalculée: Type {
    return quelqueChose
}

// FAUX ! Il n'y a pas de getter, c'est interdit
var propriétéCalculée: Type {
    set {

    }
}

// ARCHI FAUX ! Il n'y a rien du tout
var propriétéCalculée: Type {
}

C'est tout pour les propriétés calculées !

Observer les propriétés

Il existe un moyen d'observer les propriétés en Swift. Observez les propriétés, mais qu'est-ce que c'est encore que cette histoire ? Vous allez voir que c'est assez proche de ce qu'on a déjà vu.

Observer une propriété permet d'effectuer une action lorsque la propriété est modifiée.

Hé mais c'est exactement comme un setter !

Et oui exactement ! Dans notre exemple du carré, la méthode set nous permettait de modifier la longueur dès que le périmètre était modifié. Le seul souci là-dedans, c'est que set ne fonctionne qu'avec des propriétés calculées.

Il existe deux méthodes pour écouter des propriétés stockées :

  • willSet : cette méthode est appelée juste avant la modification de la propriété.

  • didSet : cette méthode est appelée juste après la modification de la propriété.

Prenons un exemple et essayons d'observer la propriété longueur :

var longueur = 1 {
    willSet {
        print("Le carré va changer de taille")
    }
    didSet {
        if oldValue > longueur {
            print("Le carré a rapetissé")
        } else {
            print("Le carré a grandi")
        }
    }
}

Dans la méthode willSet, on affiche que le carré va changer de taille, car cette méthode est appelée avant la modification.
Dans la méthode didSet, on compare l'ancienne valeur contenue dans la variable oldValue à la nouvelle valeur contenue dans longueur. En fonction du résultat, on affiche que le carré a rapetissé ou grandi. Cette méthode est appelée après la modification.

De façon similaire à oldValue, la méthode willSet a une variable newValue qui contient la nouvelle valeur. Le schéma ci-dessous résume cela :

Donc en résumé, pour observer la modification d'une propriété. On utilise :

  • set : pour les propriétés calculées

  • willSet et didSet : pour les propriétés stockées

Le cadeau

Nous avons vu dans ce chapitre un certain nombre de notions assez avancées sur les propriétés. Pour vous récompenser pour votre persévérance et vous donner une vue d'ensemble des propriétés, je vous ai concocté un petit schéma. N'hésitez pas à y revenir en cas de doute.

Exercices

Exercice 1

Observez la propriété occupiedSeats de Bus. Avant sa modification, faites afficher la phrase : "Il y a du mouvement dans le bus...". Après sa modification, faîtes afficher la phrase "X personnes viennent de monter !" ou "X personnes viennent de descendre !" selon si la valeur de la propriété augmente ou baisse.

// Ne regardez pas la correction !


































var occupiedSeats = 0 {
    willSet {
        print("Il y a du mouvement dans le bus...")
    }
    didSet {
        if oldValue < occupiedSeats {
            print("\(occupiedSeats - oldValue) personnes viennent de monter !")
        } else {
            print("\(oldValue - occupiedSeats) personnes viennent de descendre !")
        }
    }
}

Exercice 2

Ajoutez une propriété calculée en lecture seule au Bus. Cette propriété s'appellera description et contient : "Je suis un bus conduit par X avec Y personnes dedans.". X est le nom du chauffeur et Y le nombre de personnes dans le bus.

// Ne trichez pas !































var description: String {
        return "Je suis un bus conduit par \(driverName) avec \(occupiedSeats) personnes dedans."
}

En résumé

  • On peut diviser les propriétés en deux types : les propriétés stockées et calculées. Parmi, les propriétés calculées, on peut créer des propriétés calculées en lecture seule.

  • Une propriété calculée permet de modifier les getter et setter au moyen des méthodes get et set.

  • Une propriété calculée n'est jamais constante et a toujours un getter.

  • Une propriété stockée peut être observée grâce aux méthodes willSet et didSet.

Example of certificate of achievement
Example of certificate of achievement