Saltar al contenido →

Diario Swift – Día 1 – Opcionales

Tal como dije en mi último artículo del 2015, una de mis prioridades de 2016 es aprender Swift. Creo que lo mejor para eso es ir registrando en mi blog lo que voy descubriendo y aprendiendo. Seguro que a alguien podrá serle de utilidad y además a mi me ayudará a asentar los conocimientos que vaya adquiriendo.

Esta serie de artículos que empieza aquí tratará de Swift y de lo que iré aprendiendo.

¿Qué es un opcional?

La primera vez que intenté hacer algo con Swift, una de las primeras cosas que me echó para atrás fueron los opcionales. En ese momento, no entendí ni su significado, ni su funcionamiento ni mucho menos su utilidad. No estaba concentrado posiblemente y al ver ese nuevo concepto que para mi era completamente nuevo, decidí dejar de lado Swift y programar mi app con el viejo Objective C.

Swift - Meme sobre Opcionales

Empecemos con un ejemplo:

“nombre” es una variable del tipo “String?”, es decir “Optional. ¡No es un “String”! Esta variable puede contener un valor o no. No, esto no es el experimento del gato de Schrödinger.

Para utilizar esta variable, primero debemos extraer (“unwrap”) su valor. No es posible realizar ninguna acción que se realiza con un “String” antes de realizar el unwrap.

Por supuesto, es un error definir una constante como un opcional utilizando “let”. Una constante no puede ser de un tipo opcional, ya que una constante sólo puede contener un valor. Un opcional puede contener algo o puede ser nil. Definir un opcional como una constante provocará un error en tiempo de compilación.

¿Cómo se utiliza un opcional?

Existen varias técnicas para utilizar un opcional. No puedo traducir la mayoría de las expresiones porque la verdad no sabría traducir algunas palabras. De todas formas, la mayor parte de la documentación de Swift (y de programación en general) está en inglés.

Conditional binding

Este ejemplo muestra como extraer el valor utilizando una técnica llamada “Conditional binding”. Primero asignamos la variable a una constante y si esta constante no es “nil”, la utilizamos. En caso de ser nil, mostramos un mensaje indicando que la variable es “nil”. Esta manera es la que más he utilizado hasta hoy sin duda.

Forced unwrapping

Esta técnica se utiliza sólo cuando estás completamente seguro de que la variable “nombre” tiene efectivamente un valor. Al utilizar el modificador “!” estás forzando la extracción de la variable. Esto sólo funciona si la variable tiene un valor. Si la variable no tiene valor, esto provocaría un error en tiempo de ejecución. Esta técnica puede resultar peligrosa por lo tanto.

Nil coalescing

Vaya nombrecito… Esta técnica me recuerda al operador condicional y ternario “?” de php. Consiste en algo muy parecido. Comprueba si el opcional tiene un valor y si es así se lo asigna a tu constante, si no tiene valor, asigna el valor que tú indiques.

En el caso de mi ejemplo, la constante “nombreNuevo” contendrá el valor de la variable “nombre” sólo si esta contiene un valor. En cambio si no contiene nada “nil”, la constante “nombreNuevo” contendrá el valor “Miguel”. En los dos casos, la constante resultante será del tipo “String” y no será un opcional.

Optional chaining

La última técnica para extraer un valor de un opcional es utilizando Optional chaining. Esta técnica es muy utilizada cuando estás tratando con objetos Veamos el siguiente ejemplo:

“nombreAutor” contendrá el nombre del autor del artículo “p” sólo si se cumplen las siguientes condiciones:

  • “p” contiene un valor y no es “nil”. Este valor debe ser un objeto del tipo “Post”.
  • El autor de “p” contiene un valor y no es “nil”. Este valor debe ser un objeto del tipo “Persona”.
  • El nombre del autor contiene un valor y no es “nil”. Este valor debe ser un “String”.

En lugar de las […], escribo el siguiente código:

Primero, defino una variable “a” del tipo opcional “Autor”. Después inicializo “p” con el constructor por defecto. Ahora mismo “p” ya no es “nil”, contiene un valor, pero el autor de “p” sigue siendo “nil”. Por lo tanto, “nombreAutor” seguirá siendo “nil”.

Después inicializo el autor “a” con el constructor por defecto de “Persona”. Ahora, “a” ya no es “nil”, pero el nombre sigue siéndolo. Por lo tanto, la última condición sigue sin cumplirse así que “nombreAutor” sigue siendo “nil”.

Finalmente, asigno la cadena “Miguel” a la propiedad “nombre” de “a”. Por lo tanto, ahora sí, el valor de “nombreAutor” será “Miguel”.

El código todo junto:

Implicitly unwrapped optional

¿Qué significa esto? En este caso, estamos definiendo una variable opcional “String” pero indicando que contiene un valor y por lo tanto no es necesario extraerla. Es decir puedes utilizarla directamente como si fuera un String ahorrándote las técnicas para extraer el código.

El problema es que si tu variable no contiene valor, tendrás un error en tiempo de ejecución, así que ten mucho cuidado al utilizar este método.

Podrás ver que esta técnica se utiliza con los “IBOutlet”, al conectar elementos de tu vista con tu controlador. Esto es porque estos “IBOutlet” son “nil” hasta el momento en el que aparecen en pantalla. Por lo tanto en el momento en el que tu los vas a utilizar y trabajar con ellos (viewDidLoad, viewWillAppear, …), no serán “nil”. Pero en el momento de inicializar el controlador, estos elementos serán “nil”. Sólo después de cargar la vista, tendrán un valor.

¿Por qué usar un opcional?

Aunque al principio, suena raro y no lo entiendes del todo, poco a poco irás descubriendo que es muy cómodo trabajar con opcionales. La mejor manera de verlo creo que es al utilizar Optional chaining.

Volviendo al código de ejemplo que he puesto más arriba, lo volveré a escribir ahora sin utilizar opcionales y confrontaré las dos versiones.

En este caso, estoy obligado a definir valores por defecto o constructores ya que no puedo usar “nil” al no usar opcionales. Cuando creo un objeto Post, tengo que pasarle el objeto Persona. Si se puede dar el caso de que un objeto Post no tenga autor, entonces no puedo asignarlo a “nil”. Para utilizar “nil”, tengo que utilizar opcionales.

En Objective-C, lo que hacías era comprobar si tu variable era “nil” antes de utilizarlo o no? No! En Objective-C, podías programar sin preocupaciones hasta que un buen día tu app dejaba de funcionar porque la variable que tú pensabas debía contener algo, contiene “nil”. Sé sincero y reconoce que has pasado horas y horas mirando tu código sin entender por qué había fallado esto, hasta que te das cuenta que existe un remoto caso que tú no habías previsto en el que esa variable que tú pensabas que tenía que traer siempre un valor, de repente es “nil”. Los opcionales terminan con todo esto al menos en parte. Al tener que extraer el valor de las variables no podrás tener ese error. Sólo si te gusta vivir peligrosamente utilizando el método implícito podrás seguir cometiendo esos mismos errores.