La conversion de type (cast en anglais) est un moyen de vérifier le type d’une instance ou de traiter cette instance comme une super-classe ou une sous-classe de sa hiérarchie. Pour cela en Swift il y a 2 mots clés is
et as
. Ce cours va vous montrer aux travers d’exemple comme la conversion de type fonctionne en Swift.
Définition d’une hiérarchie de classe
Afin d’avoir des examples sur lesquelles s’appuyer lors de ce cours nous allons créer une hiérarchie de classe. Pour cela on va créer un véhicule comme super-classe qui contient une seule propriété et un initialiser :
class Véhicule {
let marque: String
init(marque: String) {
self.marque = marque
}
}
Un véhicule est un engin d’une certaine marque représenté ici par la propriété marque
qui est initialisé grâce à son initialiseur. Maintenant nous allons définir 2 autres types de véhicule : un vélo et une voiture. Ces 2 types vont hériter de Véhicule
et vont ajouter des propriétés spécifique à chacun :
class Voiture: Véhicule {
let nombreDePorte: UInt
init(marque: String, nombreDePorte: UInt) {
self.nombreDePorte = nombreDePorte
super.init(marque: marque)
}
}
class Vélo: Véhicule {
let toutTerrain: Bool
init(marque: String, toutTerrain: Bool) {
self.toutTerrain = toutTerrain
super.init(marque: marque)
}
}
Une Voiture
contient comme propriété le nombre de porte nombreDePorte
tandis que le Vélo
lui possède une propriété pour savoir si il est tout terrain toutTerrain
. Maintenant nous allons créer un garage qui est cimplement une liste de véhicule :
let garage: [Véhicule] = [
Voiture(marque: "Renault Clio IV", nombreDePorte: 5),
Vélo(marque: "Polygon", toutTerrain: true),
Voiture(marque: "BMW Mini", nombreDePorte: 3),
Vélo(marque: "B'Twin", toutTerrain: false)
]
Maintenant que notre cadre est bien poser nous allons nous atteler au coeur du sujet.
Vérification de type
Pour vérifier les types en Swift il faut utiliser l’opérateur is
. Cet opérateur retourne simplement un booléen en fonction du résultat :
true
: l’instance est bien du type donnéfalse
: l’instance est d’un autre type
Dans l’example ci-dessous nous allons compter le nombre d’occurence de chaque type de véhicule présent dans le garage :
var nombreDeVoiture = 0
var nombreDeVélo = 0
for véhicule in garage {
switch véhicule {
case is Voiture:
nombreDeVoiture++
case is Vélo:
nombreDeVélo++
default:
break
}
}
print("\(nombreDeVoiture) voitures et \(nombreDeVélo) vélos")
// Affiche : 2 voitures et 2 vélos
Dans cet example nous itérons au travers de notre garage
et en fonction du type de véhicule nous incrémentons la variable correspondante. Si vous n’êtes pas familier de la structure de contrôle switch
je vous conseil cet article.
La coercition descendante (Downcasting)
Une constante ou une variable d’un certain type peut en réalité se référer à un sous-type de la classe donné. Et quand vous en avez besoin vous pouvez essayer de downcaster vers cette sous classe en utilisant les opérateurs as?
ou as!
.
Le downcasting pouvant échouer l’opérateur de conversion de type est fournit sous 2 différentes formes. La forme conditionnel avec as?
qui retourne une valeur optionnelle du type vers lequel on essaye de le convertir. La seconde forme est le as!
qui lui va forcer la conversion au risque de faire planter le programme si le type donné ne peut pas être convertis.
Dans l’example ci-dessous nous allons itérer sur chaque véhicule du garage et afficher la description approprié :
for véhicule in garage {
if let voiture = véhicule as? Voiture {
print("Voiture \(voiture.nombreDePorte) de \(voiture.marque)")
}
else if let vélo = véhicule as? Vélo {
print("Vélo \(vélo.toutTerrain) de \(vélo.marque)")
}
}
// Voiture 5 de Renault Clio IV
// Vélo true de Polygon
// Voiture 3 de BMW Mini
// Vélo false de B'Twin
Dans cet example nous essayons de downcaster les véhicules vers des Voiture
et des Vélo
. Comme véhicule est de type Véhicule
il est possible que le véhicule soit l’un des sous-types. Mais comme on ne connait pas à l’avance les sous-types des variables on essaye de convertire celle-ci en utilisant l’opérateur as?
. La condition dans les if
essaye d’accéder au véhicule en tant que Voiture
ou Vélo
et si il y arrive de créer une variable temporaire du type correspondant que l’on peut utiliser ensuite dans le sous bloc de code.
Conversion de type pour les Any
et AnyObject
Swift fournit deux alias de type spéciaux pour travailler avec des types non spécifique :
AnyObject
: il peut représenter une instance de n’importe quelle classe.Any
: il peut représenter une instance de n’importe quel type (classe, struct, enum et fonction).
Quand vous utilisez des APIs de Cocoa il est fréquent de recevoir des listes de type [AnyObject]
. Cependant il est fréquent que l’on connaisse par avance le contenu de ces listes ou de ces objets. L’example ci dessous définis une liste de type [AnyObject]
dont on sait qu’ils contiennent uniquement des Voiture
:
let objets: [AnyObject] = [
Voiture(marque: "Renault Clio IV", nombreDePorte: 5),
Voiture(marque: "BMW Mini", nombreDePorte: 3)
]
for voiture in objets as! [Voiture] {
print("Voiture \(voiture.nombreDePorte) de \(voiture.marque)")
}
// Voiture 5 de Renault Clio IV
// Voiture 3 de BMW Mini
Dans cet example comme on connait les types contenu dans la liste on peut caster la liste en [Voiture]
en utilisant l’opérateur as!
.
Conclusion
J’espère que maintenant vous comprenez mieux le fonctionnement de la conversion de type en swift. Pour récapituler il y a 3 opérateurs à retenir qui sont is
, as?
et as!
qui servent respectivement à vérifier les types, à downcaster avec une vérification et à forcer le downcast.