Les propriétés static et class sont des propriétés qui appartiennent au type plutôt qu'à l'instance. Historiquement, elles sont apparues pour résoudre le problème du stockage d'informations partagées entre toutes les instances (par exemple, des compteurs, des configurations, des fabriques). En Swift, static peut être utilisé dans tous les types (class, struct, enum), tandis que class ne peut être utilisé que dans des classes et uniquement pour des propriétés calculées, permettant la redéfinition dans les sous-classes.
Problème : une mauvaise utilisation des propriétés statiques peut entraîner des conditions de course et des erreurs d'accès depuis différents threads. Il est également facile de confondre static et class et de choisir incorrectement le mécanisme pour le remplacement dans les sous-classes.
Solution :
Exemple de code :
class Counter { static var count = 0 static let queue = DispatchQueue(label: "counter.queue") static func increment() { queue.sync { count += 1 } } class var typeDescription: String { return "Compteur Générique" } } class NamedCounter: Counter { override class var typeDescription: String { return "Compteur Nommé" } }
Caractéristiques clés :
Question 1 : Peut-on déclarer une propriété static let comme propriété calculée (computed) avec get ?
Oui, une propriété static peut être à la fois stockée et calculée. Pour les propriétés let, il s'agit généralement d'une constante, mais une static var peut tout à fait être calculée :
struct Math { static var pi: Double { return 3.1415926 } }
Question 2 : Les static var sont-elles thread-safe par défaut ?
Non, si static var est modifié à partir de différents threads, des conditions de course peuvent survenir. Les opérations de lecture/écriture doivent être synchronisées manuellement.
Question 3 : Peut-on utiliser class var pour des propriétés stockées ?
Non, class var doit toujours être une propriété calculée (property with get/optional set), les propriétés stockées ne sont autorisées que pour static.
Dans une application, le compteur de connexions utilisateur était stocké dans une static var et incrémenté depuis différents threads sans synchronisation.
Avantages :
Inconvénients :
Pour un objet de configuration global, nous avons utilisé static let et l'accès à celui-ci était uniquement en lecture ou avec DispatchQueue pour écrire.
Avantages :
Inconvénients :