ProgrammationDéveloppeur iOS

Qu'est-ce que les Property Wrappers en Swift ? Comment fonctionnent-ils, pourquoi les utiliser, quelles sont les limitations et les possibilités ? Donnez un exemple de création et d'application d'un property wrapper personnalisé.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Property Wrappers — c'est un mécanisme qui permet d'incapsuler la logique de travail avec des propriétés (par exemple, validation, modifications ou stockage d'une certaine manière) et de la réutiliser pour diverses propriétés via des annotations dans le code. Ils aident à éliminer le code répétitif et à améliorer la lisibilité.

Un Property Wrapper est une structure, une classe ou un enum qui implémente le protocole property wrapper via l'annotation @propertyWrapper et la propriété obligatoire wrappedValue.

Limitations et subtilités :

  • Les Property Wrappers ne peuvent pas être appliqués aux propriétés calculées.
  • Le passage d'arguments lors de l'initialisation du wrapper peut être limité.
  • Lors de l'utilisation de plusieurs propriétés enveloppées au sein d'une structure, cela ne fonctionne correctement qu'avec les types valeur.

Exemple : Écrivons un property wrapper pour limiter automatiquement la plage de valeurs (Clamped).

@propertyWrapper struct Clamped<Value: Comparable> { var value: Value let range: ClosedRange<Value> var wrappedValue: Value { get { value } set { value = min(max(newValue, range.lowerBound), range.upperBound) } } init(wrappedValue initialValue: Value, _ range: ClosedRange<Value>) { self.range = range self.value = min(max(initialValue, range.lowerBound), range.upperBound) } } struct Person { @Clamped(0...120) var age: Int = 25 } var p = Person() p.age = 200 // Maintenant p.age = 120 p.age = -10 // Maintenant p.age = 0

Question piégeuse

Quel moyen d'accès à l'objet property wrapper original est disponible en dehors de la structure/classe où il est appliqué ?

Réponse : Via le nom de la propriété avec un soulignement (_). Par exemple, si la propriété s'appelle age, l'objet property wrapper peut être obtenu comme _age :

var p = Person() let wrapper = p._age // c'est de type Clamped<Int>

Exemples d'erreurs réelles dues à une méconnaissance des subtilités du sujet


Histoire

Dans un projet pour stocker UserDefaults, un property wrapper personnalisé a été réalisé, qui fonctionnait avec des types primitifs. Lors de son utilisation pour des types de référence (class), une fuite de mémoire inattendue est survenue — le property wrapper gardait une référence forte sur l'objet, ce qui a entraîné un cycle fort et une fuite de données. L'erreur a été corrigée en passant à une référence weak/unowned à l'intérieur de l'enveloppe.


Histoire

Dans un projet, ils ont essayé d'appliquer le property wrapper aux propriétés calculées, mais le compilateur a renvoyé une erreur : le property wrapper ne peut être utilisé qu'avec des propriétés stockées. Ce fait a été négligé, ce qui a retardé le développement du module de 2 jours.


Histoire

Lors de la création de la structure enveloppante, ils ont oublié de mettre en œuvre la syntaxe correcte d'initialisation via init(wrappedValue:...). En conséquence, il était impossible de définir des valeurs par défaut via le property wrapper, ce qui n'a été découvert qu'après l'intégration de l'enveloppe dans un grand nombre de modèles. Il a fallu revoir l'architecture.