Les structures et les classes sont des constructions polyvalentes et flexibles. Vous définissez des propriétés (variables ou constantes) et des méthodes (fonctions) pour ajouter des fonctionnalités à vos structures et classes en utilisant la même syntaxe que vous utilisez pour définir des constantes, des variables et des fonctions.
Dans Swift, vous définissez une structure ou une classe dans un seul fichier, et l'interface externe de cette classe ou structure est automatiquement mise à disposition pour d'autres codes à utiliser.
Comparaison des structures et classes
Les structures et les classes Swift ont de nombreux points communs :
- Définir des propriétés pour stocker des valeurs
- Définir des méthodes pour fournir des fonctionnalités
- Définir des indices pour donner accès à leurs valeurs via la syntaxe d'indices
- Définir des initialiseurs pour configurer leur état initial
- Être étendu pour étendre leurs fonctionnalités
- Conforme aux protocoles pour fournir des fonctionnalités standards d'un certain type
Les classes ont des capacités supplémentaires :
- L'héritage permet à une classe d'hériter des caractéristiques d'une autre.
- Le type casting vous permet de vérifier et d'interpréter le type d'une instance de classe au moment de l'exécution
- Les déinitialiseurs permettent à une instance d'une classe de libérer toutes les ressources qu'elle a affecté
- Le comptage de références autorise plusieurs références à une instance de classe
Les capacités supplémentaires prises en charge par les classes se font au prix d'une complexité accrue. En règle générale, préférez les structures car elles sont plus faciles à raisonner et utilisez les classes lorsqu'elles sont appropriées ou nécessaires.
Syntaxe des structures et classes
Les structures et les classes ont une syntaxe de définition similaire. Vous introduisez des structures avec le mot-clé struct et des classes avec le mot-clé class. Les deux placent leur définition entière dans une paire d'accolades :
struct SomeStructure {
// Définition de la structure
}
class SomeClass {
// Définition de la classe
}
struct Resolution {
// La variable width est une propriété de la structure Resolution
var width = 0
// Le type Int est implicite et donc automatiquement déduit
var height = 0
}
class VideoMode {
// Instance de la structure Resolution
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
L'exemple ci-dessus définit une nouvelle structure appelée Resolution, pour décrire une résolution d'affichage basée sur les pixels. Cette structure a deux propriétés stockées appelées width et height. Les propriétés stockées sont des constantes ou des variables regroupées et stockées dans le cadre de la structure ou de la classe. Ces deux propriétés sont déduites comme étant de type Int en les définissant sur une valeur entière initiale de 0.
L'exemple ci-dessus définit également une nouvelle classe appelée VideoMode, pour décrire un mode vidéo spécifique pour l'affichage vidéo. A noter que la dernière propriété est une valeur facultative String appelée name. Cette propriété reçoit automatiquement une valeur par défaut de nil, ou "aucune namevaleur", car il s'agit d'un type optionnel.
Instance de structure et classe : création d'un objet
let someResolution = Resolution()
let someVideoMode = VideoMode()
Les structures et les classes utilisent toutes les deux la syntaxe d'initialisation pour les nouvelles instances. La forme la plus simple de syntaxe d'initialisation utilise le nom de type de la classe ou de la structure suivi de parenthèses vides, telles que Resolution() ou VideoMode(). Cela crée une nouvelle instance de la classe ou de la structure, avec toutes les propriétés initialisées à leurs valeurs par défaut.
Accéder aux propriétés
Vous pouvez accéder aux propriétés d'une instance à l'aide de la syntaxe dot. Dans la syntaxe à point, vous écrivez le nom de la propriété immédiatement après le nom de l'instance, séparé par un point (.), sans aucun espace :
print("La largeur de résolution est \(someResolution.width)")
// "La largeur de résolution est 0"
Vous pouvez explorer les sous-propriétés, telles que la propriété width dans la propriété résolution d'un VideoMode :
print("La largeur de résolution de someVideoMode est \(someVideoMode.resolution.width)")
// "La largeur de résolution de someVideoMode est 0"
Vous pouvez également utiliser la syntaxe dot pour attribuer une nouvelle valeur à une propriété de variables :
someVideoMode.resolution.width = 1280
print("La largeur est maintenant de \(someVideoMode.resolution.width)")
// "La largeur est maintenant de 1280"
Toutes les structures ont un initialiseur membre généré automatiquement, que vous pouvez utiliser pour initialiser les propriétés de membre des nouvelles instances de structure. Les valeurs initiales des propriétés de la nouvelle instance peuvent être transmises à l'initialiseur de membre par nom :
// On créer une instance de Résolution
// mais la valeur witdh sera de 640
// celle de height sera de 480
let vga = Resolution(width: 640, height: 480)
Contrairement aux structures, les instances de classe ne reçoivent pas d'initialiseur de membre par défaut.
Les structures et les énumérations sont des types de valeurs
Un type de valeur est un type dont la valeur est copiée lorsqu'elle est affectée à une variable ou constante, ou lorsqu'elle est transmise à une fonction.
Toutes les structures et énumérations sont des types valeurs dans Swift. Cela signifie que toutes les instances de structures et d'énumérations que vous créez - et tous les types de valeurs qu'elles ont comme propriétés - sont toujours copiées lorsqu'elles sont transmises dans votre code.
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
On modifie ensuite la propriété width de cinema.
cinema.width = 2048
La vérification de la propriété width de cinema montre qu'elle a bien changé pour être 2048 :
print("cinema a une largeur de \(cinema.width) pixels")
// "cinema a une largeur de 2048 pixels"
Cependant, la propriété width de l'instance hd d'origine a toujours l'ancienne valeur de 1920 :
print("hd est toujours de \(hd.width) pixels")
// "hd est toujours de 1920 pixels"

Le même comportement s'applique aux énumérations.
Les classes sont des types de références
Contrairement aux types valeurs, les types références ne sont pas copiés lorsqu'ils sont affectés à une variable ou constante, ou lorsqu'ils sont passés à une fonction. Plutôt qu'une copie, une référence à la même instance existante est utilisée.
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
Ensuite, tenEighty est affecté à une nouvelle constante, appelée alsoTenEighty, et la fréquence d'images de alsoTenEighty est modifiée :
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
Parce que les classes sont des types de références, tenEighty et alsoTenEighty, les deux font référence à la même instance VideoMode. En fait, ce ne sont que deux noms différents pour la même instance unique, comme le montre la figure ci-dessous :

print("frameRate.property tenEighty is \(tenEighty.frameRate)")
// Prints "frameRate.property of tenEighty is now 30.0"
Cet exemple montre comment les types de références peuvent être plus difficiles à raisonner. Si tenEighty et alsoTenEighty étaient éloignés dans le code de votre programme, il pourrait être difficile de trouver toutes les façons dont le mode vidéo est changé.
Partout où vous utilisez tenEighty, vous devez également penser au code qui utilise alsoTenEighty, et vice versa. En revanche, les types de valeurs sont plus faciles à raisonner car tout le code qui interagit avec la même valeur est rapproché dans vos fichiers sources.
Opérateur d'identité
Étant donné que les classes sont des types de références, il est possible que plusieurs constantes et variables se réfèrent à la même instance unique d'une classe en arrière-plan. (Il n'en va pas de même pour les structures et les énumérations, car elles sont toujours copiées lorsqu'elles sont affectées à une constante ou une variable, ou transmises à une fonction.)
Il peut parfois être utile de savoir si deux constantes ou variables se réfèrent exactement à la même instance d'une classe. Pour cela, Swift fournit deux opérateurs d'identités :
- Identique à : ===
- Différent de : !==
Utilisez ces opérateurs pour vérifier si deux constantes ou variables font référence à la même instance unique :
if tenEighty === alsoTenEighty {
print("Se réfère à la même instance VideoMode.")
} // "Se réfère à la même instance VideoMode."
Identique à signifie que deux constantes ou variables de type classe se réfèrent exactement à la même instance de classe.
Égal à signifie que deux instances sont considérées comme égales ou équivalentes en valeur.