Property Wrappers con Swift

Llevan una temporada entre nosotros y seguro que te has cansado de verlos y usarlos mientras programas usando SwiftUI, así que hoy vamos a ver que son y para que sirven los Property Wrappers.

A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property.

The Swift Programming Language.

Es como añadir nueva funcionalidad a una variable con solo asignarle un wrapper.

¿Pero cómo se crean?

Lo primero que debemos saber es que un Property Wrapper puede ser una clase, estructura o enumeración que defina una variable llamada wrappedValue, y sí, debe llamarse así de forma obligatoria.

También debe estar marcada a su vez con @propertyWrapper.

Vamos ahora a crear un wrapper para números enteros (Int) que calcule su valor elevado a una determinado potencia.

Como hemos comentado antes, nuestro wrapper es una estructura con dos variables donde se almacena el número y la potencia a la que lo queremos elevar, además de la variable obligatoria wrappedValue.

Si nos fijamos podemos ver que hay dos inicializadores, que se usan dependiendo de si al declarar la variable marcada con nuestro wrapped le asignan un valor en el momento de la declaración o no.

Si se declara pero no se asigna un valor
Se declara la variable y se inicializa con un valor

El wrapper en acción

Ahora que lo tenemos vamos a ver como funciona nuestro wrapper

Si nos fijamos en el mensaje de consola vemos que el valor de la variable numero no se corresponde con el valor con que la inicializamos, sino que es el resultado de elevar ese número a la potencia.

Ahora bien, quizá en algún momento lo que quieras es acceder al valores y no al resultado final del wrapper, y para ello, siempre y cuando lo hagamos dentro de la clase o estructura en la que hayamos definido el wrapper, podemos usar el prefijo _ con el nombre de la variable, lo que nos dará acceso al tipo del wrapper.

Esto es así ya que este acceso sintetizado tiene un control de acceso privado

Vamos a hacer un cambio en nuestro wrapper y cambiaremos el control de acceso de las dos variables a públicos para lectura.

Y en la estructura donde tenemos definido la variable con el wrapper vamos a añadir una función show que accede al tipo wrapper.

Si creamos una variable de tipo Potencias e invocamos a la función show tendremos algo como esto

Ahora bien, si intentas usar el prefijo _ fuera del ámbito de la estructura Potencias te dará un error

error: '_numero' is inaccessible due to 'private' protection level

¿Quiere esto decir que no podremos acceder a nuestro tipo wrapper desde fuera de su ámbito de declaración? No, los chicos de Cupertino han pensado en esto también.

Projected Values

Para solucionar el problema que se nos acaba de plantear nos proporcionan los proyectes valúes.

Esto no es más que añadir una variable en nuestro wrapper llamada projectedValue con la cual exponemos un tipo que queremos que sea accesible en general.

En nuestro caso queremos dar acceso al tipo en general, por lo que devolveremos self, pero se puede devolver cualquier tipo. De nuevo vamos a modificar nuestro Wrapper

Para acceder al wrapper, en lugar de usar el prefijo _, tenemos que usar el símbolo $ (seguro que esto te suena ya mucho más)

Vamos a verlo en un ejemplo

Y ahora sí, accedemos a valor proyectado por nuestro wrapper sin problemas.