Vous écrivez les désinitialiseurs avec le mot-clé deinit, de la même manière que les initialiseurs sont écrits avec le mot-clé init. Les désinitialiseurs ne sont disponibles que sur les types de classes.

Swift désalloue automatiquement vos instances lorsqu'elles ne sont plus nécessaires, pour libérer des ressources.

En règle générale, vous n'avez pas besoin d'effectuer un nettoyage manuel lorsque vos instances sont désallouées. Cependant, lorsque vous travaillez avec vos propres ressources, vous devrez peut-être effectuer vous-même un nettoyage supplémentaire. Par exemple, si vous créez une classe personnalisée pour ouvrir un fichier et y écrire des données, vous devrez peut-être fermer le fichier avant que l'instance de classe ne soit libérée.

Les définitions de classes ne peuvent avoir qu'un seul désinitialiseur par classe.

Le désinitialiseur ne prend aucun paramètre et est écrit sans parenthèse :


deinit {
    // perform the deinitialization
}

Les désinitialiseurs sont appelés automatiquement, juste avant la désallocation de l'instance. Vous n'êtes pas autorisé à appeler un désinitialiseur vous-même.

Les désinitialiseurs de superclasse sont hérités par leurs sous-classes, et le désinitialiseur de superclasse est appelé automatiquement à la fin d'une implémentation de désinitialisation de sous-classe. Les désinitialiseurs de superclasse sont toujours appelés, même si une sous-classe ne fournit pas son propre désinitialiseur.

Une instance n'est pas désallouée tant que son désinitialiseur n'a pas été appelé, un désinitialiseur peut accéder à toutes les propriétés de l'instance sur laquelle il est appelé et peut modifier son comportement en fonction de ses propriétés (comme rechercher le nom d'un fichier qui doit être fermé).

Par exemple, la classe Bank gère une monnaie inventée, qui ne peut jamais avoir plus de 10 000 pièces en circulation. Il ne peut y en avoir qu'une seule Bank dans le jeu :


class Bank {
    static var coinsInBank = 10_000
    static func distribute(coins numberOfCoinsRequested: Int) -> Int {
        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receive(coins: Int) {
        coinsInBank += coins
    }
}

La méthode distribute(coins:) vérifie qu'il y a suffisamment de pièces dans la banque avant de les distribuer. S'il n'y a pas assez de pièces, Bank renvoie un nombre plus petit que le nombre demandé (et renvoie zéro s'il ne reste plus de pièce dans la banque). Il renvoie une valeur entière pour indiquer le nombre réel de pièces qui ont été fournies.

La classe Player décrit un joueur dans le jeu. Chaque joueur a un certain nombre de pièces stockées dans son sac à tout moment. Ceci est représenté par la propriété coinsInPurse du joueur :


class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
    }
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
    deinit {
        Bank.receive(coins: coinsInPurse)
    }
}

La classe Player définit une méthode win(coins:), qui récupère un certain nombre de pièces de la banque et les ajoute à la bourse du joueur.

La classe Player implémente également un désinitialiseur, qui est appelé juste avant qu'une instance Player ne soit libérée. Ici, le désinitialiseur renvoie simplement toutes les pièces du joueur à la banque :


var playerOne: Player? = Player(coins: 100)
print("New player in game with \(playerOne!.coinsInPurse) coins")
// Prints "New player in game with 100 coins"
print("There are now \(Bank.coinsInBank) coins left in the bank")
// Prints "There are now 9900 coins left in the bank"

Une nouvelle instance Player est créée, avec une demande de 100 pièces si elles sont disponibles. Cette instance est stockée dans une variable Player facultative appelée playerOne. Une variable optionnelle est utilisée ici, car les joueurs peuvent quitter le jeu à tout moment. L'option vous permet de savoir s'il y a actuellement un joueur dans le jeu.

Comme il s'agit d'un optionnel, elle est qualifiée par un point d'exclamation (!) lorsque sa propriété coinsInPurse est accessible pour imprimer son nombre de pièces par défaut, et chaque fois que sa méthode win(coins:) est appelée :


playerOne!.win(coins: 2_000)
print("PlayerOne won 2000, now \(playerOne!.coinsInPurse) coins")
// Prints "PlayerOne won 2000, now 2100 coins"
print("The bank now only has \(Bank.coinsInBank) coins left")
// Prints "The bank now only has 7900 coins left"

Ici, le joueur a gagné 2000 pièces. Le porte-monnaie du joueur contient désormais 2 100 pièces et la banque n'en a plus que 7 900.


playerOne = nil
print("PlayerOne has left the game")
// Prints "PlayerOne has left the game"
print("The bank now has \(Bank.coinsInBank) coins")
// Prints "The bank now has 10000 coins"

Le joueur a maintenant quitté le jeu. Ceci est indiqué en définissant la variable facultative playerOne sur nil, ce qui signifie "aucune instance Player".

Au moment où cela se produit, la référence playerOne de la variable à l'instance Player est rompue. Aucune autre propriété ou variable ne fait encore référence à l'instance Player, elle est donc désallouée afin de libérer sa mémoire. Juste avant que cela ne se produise, son désinitialiseur est appelé automatiquement et ses pièces sont renvoyées à la banque.