• ¿Qué es un lenguaje de programación?
  • Entorno de Desarrollo en macOS
WeiseRatel
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com
No Result
View All Result
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com
No Result
View All Result
WeiseRatel
No Result
View All Result
Home Lenguajes de Programación Swift

Swift – Opcionales

Josué V. Herrera by Josué V. Herrera
in Swift
Reading Time: 11 mins read
A A
Opcionales, Swift
11
SHARES
36
VIEWS
Compartir en FacebookCompartir en Twitter

Hoy aprenderemos sobre los tipos opcionales, un concepto propio y clave dentro del lenguaje Swift. Comprender los opcionales es fundamental, es una característica de uso diario, tanto en nuestro propio código como con UIKit o cualquier otro framework.

[better-ads type=’banner’ banner=’159′ ]

Pero antes respondamos la siguiente pregunta:

¿Qué es un opcional?

Un opcional en Swift es un tipo de dato que puede contener un valor o ningún valor. Los opcionales se definen agregando un símbolo de interrogación (?) al final de la anotación de tipo:

var middleName: String?

Como hay personas que no tiene middle name o segundo nombre, creo que es lógico que en cierto modelo de datos establezcamos este campo como opcional. Con lo cual informamos al compilador que esta variable puede que no contenga un valor asociado.

Imaginemos la variable middleName como un contenedor, una caja de la cual solo sabemos que puede almacenar valores de tipo String, pero no sabemos si actualmente almacena un valor o por el contrario está vacia, o mejor dicho es igual a nil.

¿Qué es Nil?

El valor especial nil (en minúsculas) establece un estado sin valor a una variable opcional.

var middleName: String?

if middleName == nil {
    
    print("La variable middleName es igual a nil!")
    
}

middleName = "Vladimir"

if middleName == nil {
    
    print("La variable middleName es igual a nil!")
    
} else {
    
    print("La variable middleName es igual al valor: \(middleName)")
    
}

Continuamos con nuestra variable middleName que al momento de declararla es igual a nil por defecto. Algo que comprobamos en el bloque if que hemos declarado a continuación. Acto seguido le asignamos un valor y nuevamente comproamos si esta es igual a nil, de lo contrario imprimimos el valor asociado.

La salida en pantalla sería la siguiente:

La variable middleName es igual a nil!
La variable middleName es igual al valor: Optional("Vladimir")

Optional

Seguramente muchos se preguntarán porque cuando imprimimos la variable middleName se muestra su valor como:

Optional("Vladimir")

Lo que sucede es que estamos viendo el envoltorio, la caja del ejemplo que les comenté. Cuando establecemos una variable como opcional y utilizamos la siguiente sintaxis (que es la recomendada):

var middleName: String?

Lo que estamos declarando es un contenedor, de tipo Optional, dentro del cual podrá haber un valor de tipo String. Por lo que el tipo String de existir siempre estará dentro de este envoltorio o wrapper (como se le llama en inglés).

[better-ads type=’banner’ banner=’160′ ]

Mientras que en una variable regular el valor de la misma se encuentra asociado directamente a esta y podemos acceder a él sin más. En el caso de las variables opcionales esto no es así, el posible valor de una variable opcional siempre se encuentra dentro de «la caja», dentro del contenedor, dentro del tipo Optional.

Así que de imprimirlo o nos devolverá nil o su valor asociado en formato Optional(VALOR).

Creo que podemos entender por qué Optional es un tipo especial. No es como Int o String, es de hecho un enum. Uno similar a este:

enum Optional<Wrapped> {
    
    case none
    case some(Wrapped)

} // Optional

Nota: Para los que tiene experiencia en otros lenguajes y saben de genéricos el Wrapped aquí es la T de toda la vida. Si por el contrario no sabes a que me refiero no te preocupes, es un tema avanzado que veremos más adelante.

Nota: Este enum es una versión simplificada del orirginal, es solo para que se entienda la lógica tras todo esto.

Mostrados los caso, que sí son fieles al original, cuando nuestra variable es igual a nil hacemos referencia al caso none y cuando tiene un valor asociado al caso some(Wrapped).

Por esta razón es que nuestra variable middleName también la podríamos inicializar de esta forma:

var middleName: Optional<String>

o también de esta otra:

var middleName = Optional<String>.none

si deseamos asociar un valor desde el inicio podemos hacerlo de la manera usual (y recomendada):

var middleName: String? = "Vladimir"

o también de esta otra:

var middleName = Optional.some("Vladimir")

Forced Unwrapping

Ahora, ¿qué hay si queremos acceder al valor como tal, al contenido de la caja sin tener que cargar con la misma? Esta pregunta es muy valida ya que con el valor empaquetado no podemos hacer mucho, por ejemplo:

var someNumer: Int? = 10

let result = someNumer + 5

Aquí lo que estamos haciendo es sumar dos valores, uno de ellos es opcional y el otro es un literal numérico, el resultado lo almacenamos en la variable result. Aunque luce como si todo estuviera bien si lo ejecutamos obtendremos un mensaje de error similar al siguiente:

error: value of optional type 'Int?' must be unwrapped to a value of type 'Int'

El error nos informa de qué debemos desempaquetar la variable opcional de tipo Int? hacia un tipo Int no opcional. Básicamente porque en el ejemplo anterior lo que estamos intentando es sumar caja + 5, cuando lo que realmente deseamos es sumar 10 + 5.

Entonces sí queremos trabajar con el valor que almacenamos en la caja, en el contenedor o wrapper, primero tenemos que sacarlo de ella.

Para esto existen varios enfoques, unos más seguros y otros más inseguros y no recomendados. Este último sería el force unwrapping o desempaquetamiento forzado si lo traducimos al castellano, ¿se dan cuenta por qué uso el nombre en inglés?

El force unwrapping es la manera más directa de acceder al valor de una variable opcional y lo hacemos mediante el signo de fin admiración («!»), siguiendo esta sintaxis:

<VARIABLE OPCIONAL>!

tal y como podemos observar en este ejemplo:

var middleName: String?

middleName = "Vladimir"

print(String(describing: middleName!))

la salida en pantalla sería:

Vladimir

nótese que hemos accedido al valor como tal y no al anterior Optional(«Vladimir»).

¿Por qué es peligroso?

Que sucedería si modificásemos el último ejemplo al siguiente:

var middleName: String?

print(String(describing: middleName!))

obtendríamos un error como este:

Fatal error: Unexpectedly found nil while unwrapping an Optional value

El mensaje de error nos informa que ha ocurrido un error fatal mientras se desempaquetaba un valor opcional, se ha encontrado nil de manera inesperada en lugar del valor esperado, en este caso String.

Por esta razón es que no se recomienda su uso, y es que por equivocación o por algun error lógico una variable opcional puede eventualmente ser igual a nil y hacer que nuestra aplicación deje de funcionar, algo que siempre debemos evitar.

Optional Binding

Al igual que el desempaquetamiento forzado (forced unwrapping), el optional binding (o enlace opcional en castellano) es una forma mucho más segura de acceder a los valores dentro del contenedor (la caja).

[better-ads type=’banner’ banner=’161′ ]

Veamos un ejemplo:

var middleName: String?

middleName = "Vladimir"

if let safeMiddleName = middleName {
    
    print("El segundo nombre del usuario es: \(safeMiddleName)")
    
} else {
    
    print("El usuario no tiene segundo nombre!")
    
}

El optional binding toma lugar en el if, y como pueden observar lo hace de una forma bastante singular. La condición de este if reside en que se pueda definir una constante apartir del valor que podría almacenar la variable opcional, caso contrario se ejecutaría el bloque else.

Este bloque if-let-else se puede leer de la siguiente forma:

Si la variable opcional middleName tiene un valor asociado define la constante safeMiddleName con el valor de middleName. De lo contrario es igual a nil, siendo así ejecuta el bloque else.

Sobre el ejemplo anterior.

Nil Coalescing

Hay ocaciones en las que necesitaremos manejar un valor por defecto en caso de que una variable opcional sea igual a nil. Para lograr esto lo primero que nos viene a la mente sería algo así:

var middleName: String?

if let safeMiddleName = middleName {
    
    middleNameTextField.text = middleName
    
} else {
    
    middleNameTextField.text = "Middle name"
    
} // else

print(middleName)

Hemos modificado un poco el ejemplo anterior y establecemos un escenario donde estamos rellenando los datos del usuario en el clásico formulario donde el usuario puede editar sus datos.

En este caso solo nos referimos al campo de segundo nombre (middleNameTextField) al cual asignamos un placeholderen en caso de la variable opcional (middleName) ser igual a nil,.

Nota: En un entorno real un objeto UITextField tendría un placeholder asociado por defecto desde un inicio y no precisamente en el atributo text, para este fin contamos con el atributo placeholder. Este ejemplo es solo con fines didácticos.

Este enfoque soluciona el problema, pero aún así podemos abogar por una mejor alternativa mediante el operador ternario, de esta manera:

middleNameTextField = middleName != nil ? middleName! : "Middle name"

Si bien es cierto que hemos logrado lo mismo en una sola línea, Swift nos ofrece una opción mucho más óptima. Me refiero al nil coalescing operator o operador de coalescencia nil:

middleNameTextField = middleName ?? "Middle name"

Mediante el nil coalescing operator logramos lo mismo pero de una manera mucho más compacta y conscisa, más legible. Si middleName es igual a nil, se retorna el valor que hemos especificado a la derecha, de lo contrario el valor asociado a la variable opcional.

Optional Chaining

El encadenamiento opcional (o también optional chaining) es una característica que nos permite acceder a propiedades, métodos y subíndices de objetos que son opcionales, con lo cual podrían ser igual a nil.

[better-ads type=’banner’ banner=’161′ ]

A diferencia del desempaquetamiento forzado (forced unwrapping) que da lugar a una excepción en tiempo de ejecución cuando se encuentra con nil, el optional chaining ha sido diseñado para sobrevivir a nil y es sumamente util. Veamos:

struct Person {
    
    let name: String
    
    var car: Car?
    
} // Person

struct Car {
    
    let brand: String
    
    var vehicleInspection = false
    
} // Car

let client = Person(name: "Oscar", car: nil)

if let inspection = client.car?.vehicleInspection {
    
    if inspection {
        
        print("INFO: El cliente tiene carro y ha hecho la inspección del mismo.")
        
    } else {
        
        print("ADVERTENCIA: El cliente tiene carro y no ha hecho la inspección del mismo.")
        
    } // else

} else {
    
    print("INFO: El cliente no tiene carro!")
    
} // else

En este ejemplo planteamos un escenario donde tenemos dos estructuras, una referente a una persona y otra a un carro. Una persona puede o no tener un carro así que dentro de la estructura Person incluímos el carro como opcional. El carro por su parte incluye una propiedad boleana donde establecemos si el ha carro ha pasado la revisión técnica o no.

En otro segmento de nuestro código nos surge la necesidad de verificar, si el carro del cliente ha pasado la revisión.

¿Qué sucedería si queremos comprobar el valor de vehicleInspection pero el cliente no tiene carro?

Si el cliente no tiene carro nos encontraremos con un nil al tratar de acceder a la propiedad que deseamos, porque de hecho no existirá instancia alguna.

Para tener esta posibilidad bajo control tenemos el optional chaining en Swift, y este consiste en anteponer el signo de interrogación (?) al punto que nos da acceso a las propiedades y métodos de la instancia.

client.car?.vehicleInspection

Cada vez que veamos algo así ya sabemos que car (en este caso) es opcional y el signo de interrogación nos ayuda a validar el estado actual de car. Si el cliente no tiene carro pues car será igual a nil y este es el valor que se retorna, en casi de tener un objeto Car asociado entonces podemos seguir la cadena al próximo eslavón (vehicleInspection en este caso).

Conclusiones

Creo que se ha entendido todo bastante bien, no obstante todo es cuestión de práctica y los Opcionales son una caracteristica de uso diario en Swift y poco a poco se volverán algo bien natural.

Los Opcionales brindan flexibilidad al lenguaje y cuando decimos que Swift es un lenguaje con un enfoque en la seguridad, los Opcionales también son parte de esto.

Falta aún mucho por aprender en nuestro camino a convertirnos en iOS Developer. Suscríbete a nuestra lista de correo y síguenos en nuestras redes sociales. Mantente al tanto de todas nuestras publicaciones.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

¡Cualquier duda o sugerencia, ya sea errores a corregir o ejemplos a añadir, será más que bienvenida, necesaria!

Josué V. Herrera

Josué V. Herrera

Desarrollador Swift / iOS. Llevo en el mundo de la informática más de 15 años, trabajado con varios lenguajes de programación y frameworks como Swift, C++ / Qt, C#, Java, entre otros. También he fungido como administrador de redes, bases de datos y sistemas Linux (algún que otro BSD) desde 2005 hasta la actualidad. Soy “Experto en Administración y Seguridad de Redes” por la Universidad Tecnológica Nacional FRVM de Córdoba, Argentina.

Artículos relacionados

La Sentencia Guard, Swift
Swift

Swift – La Sentencia Guard

Funciones de Órden Superior, Swift
Swift

Swift – Funciones de Órden Superior

¿Cómo iterar sobre tipos de datos propios?, Swift
Swift

Swift – ¿Cómo iterar sobre tipos de datos propios?

Trabajo con Fechas, Swift
Swift

Swift – Trabajo con Fechas

Load More
5 1 votar
Article Rating
Suscríbete
Login
Notificar de
guest

guest

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

0 Comments
Inline Feedbacks
Ver todos los comentarios

Suscríbete

Únete!

Únete!

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!

Entradas recientes

  • Estructuras de Datos – Lista Enlazada
  • MariaDB – Comandos Básicos
  • MariaDB – Instalación y Configuración
  • ¿Cómo hacer una instalación limpia de macOS Ventura?
  • Git – Instalación y Configuración

Categorías

  • Bases de Datos (2)
    • MariaDB (2)
  • Estructuras de Datos (3)
  • Gestión de Dependencias (2)
    • Swift Package Manager (2)
  • Git (2)
  • Guías (2)
  • Lenguajes de Programación (27)
    • Swift (27)
  • Sobre WiseRatel.com
  • Política de Privacidad
  • Política de Cookies
  • ¿Hablamos?
Powered by humans!

© 2022 WeiseRatel. All Rights Reserved.

No Result
View All Result
  • ¿Qué es Swift?
  • ¿Hablamos?
  • Sobre WeiseRatel.com

© 2022 WeiseRatel. All Rights Reserved.

wpDiscuz
RECIBE CONTENIDO SIMILAR EN TU CORREO

RECIBE CONTENIDO SIMILAR EN TU CORREO

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!

Cookies Para que este sitio funcione adecuadamente, a veces instalamos en los dispositivos de los usuarios pequeños ficheros de datos, conocidos como cookies. La mayoría de los grandes sitios web también lo hacen.
Aceptar cookies
Leer más
Ajustes de cookies
Configuración de Cookie Box
Configuración de Cookie Box

Ajustes de privacidad

Decida qué cookies desea permitir. Puede cambiar estos ajustes en cualquier momento. Sin embargo, esto puede hacer que algunas funciones dejen de estar disponibles. Para obtener información sobre eliminar las cookies, por favor consulte la función de ayuda de su navegador. MÁS INFORMACIÓN SOBRE LAS COOKIES QUE USAMOS.

Con el deslizador, puede habilitar o deshabilitar los diferentes tipos de cookies:

  • Block all
  • Essential
  • Functionality
  • Analytics
  • Advertising

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado

Este sitio web no

  • Recordar los datos de inicio de sesión
  • Funcionalidad: Recordar los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado
  • Funcionalidad: Recordar todos los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados

Este sitio web no

  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Esencial: Recordar sus ajustes de permisos de cookies
  • Esencial: Permitir cookies de sesión
  • Esencial: Recopilar la información que introduzca en el formulario de contacto de un boletín informativo y otros formularios en todas las páginas
  • Esencial: Hacer un seguimiento de lo que introduzca en la cesta de la compra
  • Esencial: Verificar que ha iniciado sesión en su cuenta de usuario
  • Esencial: Recordar la versión del idioma seleccionado
  • Funcionalidad: Recordar todos los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas

Este sitio web no

  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web

  • Funcionalidad: Recordar los ajustes de redes sociales
  • Funcionalidad: Recordar el país y la región seleccionados
  • Análisis: Hacer un seguimiento de las páginas visitadas y de la interacción en las mismas
  • Análisis: Hacer un seguimiento de la ubicación y la región según la dirección IP
  • Análisis: Hacer un seguimiento del tiempo pasado en cada página
  • Análisis: Aumentar la calidad de los datos de las funciones estadísticas
  • Publicidad: Adaptar la información y la publicidad a sus intereses según, p.ej., el contenido que ha visitado antes. (Actualmente no usamos segmentación ni cookies de segmentación)
  • Publicidad: Recopilar información personalmente identificable como el nombre y la ubicación

Este sitio web no

  • Recordar los datos de inicio de sesión
Guardar cerrar