Property Wrappers son un mecanismo que permite encapsular la lógica de trabajo con propiedades (por ejemplo, validación, cambios o almacenamiento de una manera específica) y reutilizarla para diferentes propiedades mediante anotaciones en el código. Ayudan a eliminar el código repetido y aumentar la legibilidad.
Un Property Wrapper es una estructura, clase o enum que implementa el protocolo de property wrapper a través de la anotación @propertyWrapper y la propiedad obligatoria wrappedValue.
Limitaciones y detalles:
Ejemplo: Escribiremos un property wrapper para limitar automáticamente el rango de valores (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 // Ahora p.age = 120 p.age = -10 // Ahora p.age = 0
¿Qué forma de acceso al objeto de property wrapper original está disponible fuera de la estructura/clase donde se aplica?
Respuesta: A través del nombre de la propiedad con un guion bajo (_). Por ejemplo, si la propiedad se llama age, el objeto de property wrapper se puede obtener como _age:
var p = Person() let wrapper = p._age // este es del tipo Clamped<Int>
Historia
En un proyecto para almacenar UserDefaults se implementó un property wrapper personalizado que trabajaba con tipos primitivos. Al intentar usarlo con tipos de referencia (class) surgió una fuga de memoria inesperada: el property wrapper mantenía una referencia fuerte al objeto, lo que provocaba un ciclo fuerte y una fuga de datos. El error se corrigió pasando a una referencia weak/unowned dentro del wrapper.
Historia
En el proyecto, se intentaron aplicar property wrappers a propiedades calculadas, pero el compilador emitió un error: el property wrapper solo puede ser utilizado con propiedades almacenadas. Este hecho se pasó por alto, lo que retrasó el desarrollo del módulo durante 2 días.
Historia
Al crear la estructura de wrapper, olvidamos implementar la sintaxis correcta de inicialización a través de init(wrappedValue:...). Como resultado, no se podían establecer valores predeterminados a través del property wrapper, lo que solo se reveló después de integrar el wrapper en un gran número de modelos. Tuvimos que revisar la arquitectura.