Class est un type par référence (reference type) dans le langage Swift, dont les instances sont passées par référence plutôt que copiées lors de l'affectation. Contrairement aux structures, les classes prennent en charge l'héritage, la déinitialisation et le comptage automatique des références ARC pour la gestion de la mémoire. Selon le Swift Programming Language Guide, 2026, class est nécessaire pour travailler avec les frameworks d'UI d'Apple (UIKit, AppKit) et implémenter des motifs nécessitant une identité partagée d'objet. Le choix entre class et struct est l'une des décisions architecturales clés en Swift.
Points essentiels
Class — un type composé par référence en Swift qui regroupe propriétés et méthodes en une entité unique avec prise en charge de l'héritage et de la répartition dynamique. Contrairement à struct, une instance de classe est créée dans le tas, et une variable stocke une référence à cette instance, et non les données elles-mêmes.
Lorsque vous assignez une variable de classe à une autre variable, toutes deux référencent le même objet en mémoire. Les modifications via une référence sont visibles via l'autre — c'est une propriété fondamentale des types par référence, utilisée dans les motifs de délégation, d'observation et d'état partagé.
Selon la Documentation Apple Swift, les classes sont le seul moyen de travailler avec UIKit et AppKit, où tous les composants d'UI héritent de UIView et UIViewController. De plus, les classes sont nécessaires pour implémenter des motifs qui nécessitent l'identité d'objet (deux références vers un objet) et une durée de vie contrôlée.
La sémantique de type par référence — la propriété clé des classes. Lors de l'assignation d'une classe à une nouvelle variable, Swift copie la référence, pas les données. Toutes les variables qui référencent la même instance voient son état actuel et peuvent le modifier. Ce comportement diffère fondamentalement des types par valeur, où chaque variable obtient une copie indépendante.
// Exemple de sémantique de type par référence
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — même référence
user2.name = "Bob"
print(user1.name) // "Bob" — modifié via user2 !
// Vérification d'identité avec l'opérateur ===
print(user1 === user2) // true — même objet
Les opérateurs === (identité) et !== vérifient si deux variables référencent la même instance de classe. Cela diffère de == (égalité), qui compare les valeurs des propriétés. L'opérateur === n'est pas disponible pour struct — les types par valeur n'ont pas d'identité.
Héritage — un mécanisme par lequel une classe peut adopter les propriétés et méthodes d'une classe parente. En Swift, une classe ne peut hériter que d'un seul parent (héritage simple), mais peut implémenter plusieurs protocoles. Le mot-clé override permet de redéfinir une méthode ou propriété héritée.
Toute classe qui n'hérite pas d'une autre classe devient automatiquement une classe de base (à ne pas confondre avec NSObject). Une sous-classe spécifie le parent avec deux-points après son nom. Si une sous-classe redéfinit une méthode du parent, elle doit appeler super.méthode() pour préserver le comportement du parent — c'est une exigence du compilateur.
Le mot-clé final avant class empêche l'héritage. Le compilateur peut optimiser les appels de méthodes d'une classe finale via une répartition statique, améliorant ainsi les performances. Utilisez final pour les classes non destinées à l'extension — cela documente votre intention et accélère le code.
// Exemple d'héritage de classes en Swift
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car hérite de Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// Classe finale — empêche l'héritage
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
L'héritage est un mécanisme puissant mais responsable. Les hiérarchies profondes (plus de 5 niveaux) compliquent la maintenance et les tests. Pour la réutilisation fonctionnelle sans héritage, utilisez des protocoles avec extension et la programmation orientée protocole — une approche qu'Apple promeut comme alternative aux hiérarchies de classes profondes.
Swift utilise ARC (Comptage Automatique des Références) pour la gestion de la mémoire des classes. Chaque instance de classe possède un compteur de références fortes. Lorsqu'une nouvelle référence forte est créée, le compteur augmente ; lorsqu'elle est détruite, il diminue. Lorsque le compteur atteint zéro, la mémoire est libérée.
Deinit — méthode appelée automatiquement avant la libération d'une instance de classe. Elle libère des ressources : ferme des fichiers, se désabonne des notifications, arrête des minuteries. Deinit n'est disponible que pour les classes — les structures et énumérations ne l'ont pas.
Pour prévenir les cycles de références fortes (retain cycles), Swift fournit des références weak et unowned. Weak est une référence optionnelle qui devient automatiquement nil lorsque l'objet est libéré. Unowned n'est pas optionnelle mais référence un objet garanti de vivre plus longtemps que le contexte actuel. Un cycle de rétention typique se produit dans une relation parent-enfant : l'enfant maintient une référence forte au parent.
// Exemple d'ARC et de référence faible
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) désalloué") }
}
class Child {
var name: String
weak var parent: Parent? // weak empêche le cycle de rétention
init(name: String) { self.name = name }
deinit { print("\(name) désalloué") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // Les deux objets désalloués !
// Sans weak, cela créerait un cycle de rétention
Utilisez toujours weak pour les références d'un objet enfant vers le parent et pour les listes de capture dans les closures. Utilisez unowned uniquement lorsque vous êtes sûr que l'objet survivra au contexte actuel — une utilisation incorrecte d'unowned peut provoquer un crash lors de l'accès à une mémoire libérée.
Le choix entre class et struct est une décision architecturale qui affecte les performances, la sécurité des threads et la conception d'API. Considérez le tableau des différences clés pour prendre la bonne décision dans chaque cas.
| Caractéristique | class | struct |
|---|---|---|
| Type | Type par référence | Type par valeur (copie) |
| Mémoire | Tas + ARC | Pile / inlined |
| Héritage | Prend en charge (parent unique) | Ne prend pas en charge |
| Deinit | Disponible | Non disponible |
| Identité (===) | Prend en charge | Ne prend pas en charge |
| Mutating | Non requis (toujours mutating) | Uniquement avec mutating |
| Init memberwise | Non généré | Généré automatiquement |
| Sécurité des threads | Non garantie (état partagé) | Garantie (copie) |
Utilisez les classes lorsque vous avez besoin d'identité partagée (plusieurs parties du code travaillant avec un objet), d'héritage ou d'interaction avec l'environnement d'exécution Objective-C. Pour tout le reste, les structures sont préférables — elles sont plus rapides, plus sûres dans le code multithread et ne nécessitent pas de gestion de la mémoire.
Malgré la recommandation d'Apple d'utiliser struct par défaut, les classes sont nécessaires dans plusieurs scénarios spécifiques. Examinons chacun avec des exemples pratiques.
Tous les composants d'UI sur iOS et macOS sont des classes qui héritent de UIView (iOS) ou NSView (macOS). Vous ne pouvez pas remplacer UIViewController par une struct — il nécessite l'héritage et deinit pour libérer les ressources. Lorsque vous travaillez avec UIKit, utilisez des classes pour les contrôleurs, les vues et leurs délégués.
Le motif Singleton (une instance de classe pour toute l'application) nécessite une sémantique de référence. Les gestionnaires : NetworkManager, SettingsManager, AnalyticsService — sont généralement implémentés comme des classes avec une propriété statique partagée. Les structures ne conviennent pas car chaque copie serait une instance indépendante.
Lorsqu'un objet doit être la source unique de vérité et est passé entre modules par référence — utilisez class. Cela s'applique à la gestion d'état, où la modification d'un objet à un endroit doit être visible dans tous les composants dépendants. Pour ObservableObject dans SwiftUI, les classes sont obligatoires.
// ObservableObject — class requise pour SwiftUI
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// Utilisation dans une vue SwiftUI
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "Bienvenue" : "Connexion")
}
}
Règle : si un objet doit avoir une identité (deux références -> un objet), être une instance unique ou fonctionner avec UIKit/Objective-C — choisissez class. Si un objet contient simplement des données — choisissez struct.
Questions fréquentes
Class est un type par référence en Swift qui prend en charge l'héritage, la déinitialisation et l'ARC pour la gestion de la mémoire. Les instances de classe sont stockées dans le tas et les variables contiennent une référence à l'objet, pas sa copie.
Class — type par référence (passé par référence), prend en charge l'héritage et deinit. Struct — type par valeur (copié), ne prend pas en charge l'héritage, mais implémente des protocoles et obtient automatiquement un init memberwise. Swift recommande struct comme type par défaut.
ARC (Comptage Automatique des Références) — un mécanisme de gestion de la mémoire pour les classes Swift. Chaque instance possède un compteur de références fortes. Lorsque le compteur atteint zéro, la mémoire est libérée. Les références weak et unowned empêchent les cycles de rétention entre les objets.
Deinit — une méthode de classe appelée automatiquement avant la libération de sa mémoire. Utilisée pour fermer des fichiers, se désabonner des notifications et autres opérations de nettoyage. Deinit n'est disponible que dans les classes — les structures ne l'ont pas.
Utilisez class pour les composants d'UI UIKit/AppKit, le singleton, ObservableObject dans SwiftUI, les objets avec identité partagée (délégué, observateur) et lors du travail avec l'environnement d'exécution Objective-C. Pour les modèles de données, DTO et configurations, struct est préférable.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi