Opcionales en Swift

Opcionales Swift

Una de las ventajas que nos da Swift es la posibilidad de escribir código seguro. Esto implica que este lenguaje está preparado para que el programador no se encuentre con situaciones indeseadas al momento de ejecutar su código, sino que tome los recaudos mientras codifica. Los opcionales son un mecanismo muy importante que coopera en esta dirección.

Opcionales – Definición

Los opcionales permiten indicar que un valor puede estar ausente. Esto significa que una variable opcional puede tener un valor y por lo tanto se puede acceder al mismo o que esa variable esta “vacía”.

La potencia de este enfoque es que si se sabe que una variable puede llegar a no tener valor en algún momento de su ciclo de vida, debemos escribir código adicional preguntando si ese valor existe o no. Esto da la ventaja de estar seguros en todo momento sobre qué hacer en cada caso. Si no existieran los opcionales, puede darse el caso de que no contemplemos un escenario en donde el valor no exista y por lo tanto se generen comportamientos extraños en momentos de ejecución.

Veamos un ejemplo:

[code lang=”Swift”]
let colores = ["azul", "negro", "verde", "rojo", "amarillo"]

let primerColor = colores.first

//primerColor es es String? en lugar de String
[/code]

Primero definimos un array de String en donde guardamos un listado de colores y luego, creamos una constante para obtener el primero color del arreglo usando la propiedad first. Como puede darse el caso de que el arreglo esté vacío, first no siempre va a devolver un valor; en algunos casos tomará el primer elemento pero en otros indicará que no se encontró un valor. Esto hace que el resultado sea un opcional.

nil

Volviendo al ejemplo anterior, para indicar la ausencia de un valor se usa un valor especial llamado nil. Por lo tanto, la constante primerColor no se trata de un tipo String sino de un opcional de String, indicado con un signo de pregunta (?) String?.

Si quisiéramos definir una variable como opcional usamos la siguiente forma:

[code lang=”Swift”]
var segundoColor: String? = "negro"
print("\(segundoColor)")

//Devuelve:
//Optional("negro")

segundoColor = nil
print("\(segundoColor)")

//Devuelve:
//nil
[/code]

Como vemos, definimos la variable indicando el tipo de dato y agregando un signo de pregunta para indicar que se trata de un opcional. La asignación de un valor en ese momento es optativo, ya que de no hacerlo Swift infiere que su valor inicial es nil. Luego, si imprimimos esa variable usando print vemos que su valor es Optional(“negro”) en lugar de “negro” a secas. Por último, una variable opcional puede volver a valer nil si es necesario.

Nota
Recordemos que las variables no opcionales deben tener un valor al momento de su definición obligatoriamente.

Opcionales – Forced unwrapping

Si sabemos y estamos seguros que en un determinado momento una variable opcional tiene un valor en su interior, podemos usar la técnica de forced unwrapping (desenvoltura forzada) mediante el uso de un signo de exclamación al final del nombre de la variable (!):

[code lang=”Swift”]
var otroColor:String? = "celeste"

print("\(otroColor!)")

//Devuelve
//celeste
[/code]

Como sabemos que la variable otroColor contiene un valor, usamos la desenvoltura forzada y accedemos al dato que el mismo encierra. Ya no estamos obteniendo un Optional(“celeste”) sino que directamente obtenemos “celeste”.

Si quisiéramos preguntar primero si esa variable vale nil o no, una posibilidad es usar una sentencia if:

[code lang=”Swift”]
if otroColor != nil {
print("\(otroColor!)")
}

//Devuelve
//celeste
[/code]

En este caso, primero nos aseguramos si la variable no vale nil (o sea, si tiene un valor) y luego hacemos el forced unwrapping, debido a que dentro del if estamos seguros que esa variable tiene un valor.

Para más información sobre el uso del if u otras técnicas condicionales, podes consultar el capitulo de control de flujo.

Opcionales – Optional Binding

Si bien el enfoque anterior es perfectamente válido, no termina siendo muy cómodo si dentro del if se necesita usar muchas veces el valor dentro del opcional, ya que tendríamos que recordar de usar el ! en todos los casos.

Otra manera de hacer lo mismo pero un poco más eficiente es usando el optional binding (enlace opcional), en el cual se pregunta si un opcional contiene un valor y en caso afirmativo, se crea una constante o variable temporal para ser usada dentro del if o while como si se tratara de una versión no opcional. Una vez fuera de ese if o while, la misma deja de existir.

[code lang=”Swift”]
if let colorElegido = otroColor {
print("El color elegido es \(colorElegido)")
}

//Devuelve:
//El color elegido es celeste
[/code]

Como vemos, creamos una constante temporal llamada colorElegido que contiene el valor del opcional otroColor. Dentro del if usamos ese valor y ya fuera de él la constante ya no existe más.

Asimismo, podemos anidar varios enlaces opcionales e incluso usar otras comparaciones convencionales que devuelven true o false. Como resultado, se ingresará al if siempre que todos los opcionales tengan un valor y todas las condiciones devuelvan true. Si alguno de estos casos no se da, el resultado final será false y no se ingresará al if.

[code lang=”Swift”]
let numeroPar = 30

if let colorElegido = otroColor, let numero = Int("45"), numeroPar < 50 {
print("El color elegido es \(colorElegido) y el \(numeroPar) es menor a 50")
print("\(numero)")
}

//Devuelve:
//El color elegido es celeste y el 30 es menor a 50
//45
[/code]

Opcionales – implicity unwrapped optionals

En muchas situaciones contamos con variables opcionales que en un momento determinado del programa son inicializados con un valor y que luego no van a volver a valer nil nunca más. Por tal motivo, es conveniente no tener que preguntar a cada instante si esa variable contiene un valor y hacer la desenvoltura correspondiente, ya que se asume que siempre se va a contener un valor.

Un ejemplo muy claro de este escenario se da cuando se programa para un sistema operativo como iOS, en donde los botones que vemos en pantalla al inicio de su ciclo de vida se crean en nil pero luego mientras se inicializan determinados componentes, las variables que hacen referencia a esos botones contienen valor, hasta tanto el usuario cambia de pantalla y se pierden esas referencias. Como en un momento de su ciclo de vida necesitó valer nil, es obligatorio usar un opcional, pero como luego siempre va a tener un valor, no es cómodo tener que usar un if let en cada uso. Para este tipo de casos, los implicity unwrapped optionals (opcionales desenvueltos en forma implícita) son ideales.

Para hacer uso de ellos, en lugar de declarar al opcional usando un signo de pregunta (?) se utiliza un signo de exclamación (!):

[code lang=”Swift”]
let posibleValor:String? = "Estamos aprendiendo Swift! Yeahh!"
let valorSeguro:String! = posibleValor!

print(posibleValor)
print(valorSeguro)

//Devuelve:
//Optional("Estamos aprendiendo Swift! Yeahh!")
//Estamos aprendiendo Swift! Yeahh!
[/code]

Podríamos decir que este tipo de opcionales tienen realizan la desenvoltura de su valor en forma automática, sin necesidad de hacerlo explícito. Tengamos en cuenta que si una variable o constante vale nil e intentamos usar su valor, vamos a tener un error en tiempos de ejecución. Por lo tanto, hay que ser muy cuidadoso y pensar bien antes de usar este tipo de opcionales.

En el caso de que exista alguna posibilidad de que una variable se vuelva nil en algún momento del código, entonces no debemos usar este opcional implícito.

Por otro lado, si necesitamos preguntar si ese opcional implícito tiene un valor en su interior o si quisiéramos usar el optional binding, podemos hacerlo:

[code lang=”Swift”]
if valorSeguro != nil {
print(valorSeguro)
}

if let dato = valorSeguro {
print(dato)
}
[/code]

Opcionales – nil-coalescing operator

Este operador, que podríamos traducirlo como operador que viene junto a nil, devuelve el valor que contiene un opcional haciendo una desenvoltura (a) y en caso de encontrar nil, devuelve otro valor (b). Su sintaxis es a ?? b.

Un punto a tener en cuenta es que tanto a como b deben ser del mismo tipo.

[code lang=”Swift”]
var animal:String? = "Perro"

let mascota = animal ?? "Gato"

print("\(mascota)")

//Devuelve Perro
[/code]

En el ejemplo, definimos una variable opcional animal con el valor Perro. Al ser opcional, podría no contener un valor (ser nil). Luego se declara una constante mascota que va a valer Perro siempre que la variable animal tenga ese valor. En caso de ser nil, se incluye un valor adicional Gato.

Este operador es muy útil cuando queremos dar un valor por defecto en caso de que una variable o contante no tengan valor.

Descargar archivo playground.
Siguiente capítulo: Funciones.

Si quieres aprender más sobre que es iOS sigue este enlace con una guía definitiva sobre el mejor Sistema Operativo para móviles.
¿Te ha gustado este artículo?
Opcionales en Swift Overall rating: ★★★★★ 4.7 based on 8 reviews
5 1

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *