Saltar al contenido
KodigoSwift

Tutorial Swift – La Sentencia Guard

Tutorial Swift - La Sentencia Guard

En el Tutorial Swift de hoy hablaremos sobre la sentencia guard, aprenderemos a usarla correctamente y sobre todo analizaremos varios ejemplos donde es bien útil, aunque muchas veces algunos la vean como algo redundante, inútil y de la cual podemos prescindir.

Básicamente la sentencia guard funciona de manera parecida a if ya que ejecuta un código basado en una expresión booleana. Pero a diferencia de if el código dentro del bloque guard solamente se ejecuta si la condición no se cumple, es decir cuando es false. Luego de esta explicación quizás muchos pensarán lo mismo: claramente el comportamiento de guard puede ser sustituido fácilmente por if y esto es cierto… lo que sucede es que la razón de la existencia de guard viene dada por características intrínsecas que la hacen diferente y no por oscuros deseos de confundirte aún más en tu proceso de aprendizaje.

La Pirámide de la Perdición

Antes de continuar hablando de guard creo que debemos entender la necesidad tras su uso. Comencemos por imaginar que tenemos una pantalla donde vamos a registrar nuevos usuarios. Hay cuatro campos donde se especificará el nombre, correo electrónico, un password y la confirmación del mismo, por último un botón con el cual enviaremos estos datos hacia nuestra base de datos:

Aquí tenemos una clásica Pyramid of Doom (pirámide de la perdición), un código horrible y que debemos de evitar a toda costa. El enfoque tras este código básicamente se resume en que la constante generada con:

…solamente puede ser usada desde dentro del ámbito de las llaves de este bloque if. Así que el programador luego de comprobar que nameEdit no es nil pues anida la comprobación de emailEdit y así consecutivamente hasta llegar a la línea 18 donde necesita poder acceder a todas las constantes antes creadas en pos de poder almacenarlas, generando así la antes mencionada pirámide de la perdición.

En la línea 53 hemos comentado la inicialización de passwordlEdit en pos de comprobar nuestro horrible código, obteniendo la siguiente salida en pantalla:

Al mismo tiempo si eliminamos el comentario sobre la línea 53 la salida sería la esperada:

Creo que está de más decir que hay mejores opciones al código anterior, más legibles y fáciles de mantener.

Salida Temprana

Un mejor enfoque sería el de una Salida Temprana, que no es más que aquel donde primero comprobamos los datos con los que trabajaremos, o en este caso que los campos de texto no sean nil y que tampoco estén vacíos:

…para al final añadir el nuevo registro luego de todas las validaciones.

El problema con este código es que no compila y de hecho muchas veces este último ejemplo es el que genera la pirámide de la perdición, en un esfuerzo por corregir los 5 errores que nos informa Xcode. Uno de estos:

La razón tras estos errores es la que ya comentamos: el tiempo de vida de las constantes creadas con “if let” está limitado al ámbito de ese bloque if. Por ende el compilador no puede encontrar en la línea 35 ninguna referencia a las constantes password o confirm y de igual manera sucede en la línea 43 con name, email y password.

En este punto la única manera de salvar el código anterior sería desempaquetar nuevamente todas las variables opcionales (name, email, password…), siempre asegurándonos de que todas las comprobaciones ya han sido efectuadas:

…por lo que añadimos este código a continuación del último bloque “if let“. Con esto logramos que las instrucciones que vienen a continuación puedan encontrar las referencias correspondientes.

¿Por qué hemos dicho entonces que este era un mejor enfoque?

Pues porque realmente lo es, el problema lo ha generado “if let” y evidentemente hay una solución mucho más elegante y legible a una horrible pirámide de la perdición o al parche que acabamos de comentar.

Transferencia de Control

El objetivo de guard es alterar el control de flujo de un programa, usualmente dentro del ámbito de un ciclo o de una función, tal y como ya hemos explicado esto ocurre siempre y cuando una o varias de las condiciones no sean válidas. Una característica que viene como anillo al dedo para un enfoque Early Exit (salida temprana)… vamos que se presta de manera natural a servir de validación para nuestras funciones.

Teniendo en cuenta la forma que adopta la sentencia guard:

…y que en la sección <código> sería donde bifurcaríamos la ejecución de nuestra aplicación. Una sección donde entre otros códigos podríamos especificar una de estas expresiones:

  • return
  • break
  • continue
  • throw

…sin más, los problemas que teníamos con el código anterior los podemos corregir con algunas pocas modificaciones:

En un análisis rápido ya podemos percatarnos de que guard nos ayuda con la legibilidad al permitirnos vigilar por las condiciones que deseamos. Por ejemplo cuando especificamos:

…estaríamos expresando la intención de:

“vigilar la correcta creación de la constante name al desempaquetar nameEdit?.text al mismo tiempo que name no puede ser igual a “” y en caso de serlo pues ejecutaríamos el código dentro de las llaves, momento donde interrumpimos la ejecución de la función transfiriendo el control de flujo fuera de la misma.”

Pero la principal característica de guard, que también salta a la vista, es que podemos acceder a las constantes ya desempaquetadas y fuera del ámbito de sus llaves a diferencia de cuando usamos “if let“, algo que claramente nos da mucha más flexibilidad y nos ayuda a crear código más limpio y fácil de mantener.

Bucles

La instrucción guard también es útil cuando trabajamos con bucles. Veamos otro ejemplo:

Hemos adoptado un enfoque de salida temprana (o en este caso de salto temprano ?), las primeras instrucciones que ejecutamos son aquellas que verifican si se cumplen o no los requisitos que hemos establecido, si estas devuelven true el ciclo actual se interrumpe y saltamos al siguiente.

Aunque el código anterior funciona, a mi modo de ver, la línea 5 no luce muy legible y quizás para algunos sí un poco críptica:  nuevamente estamos verificando por casos que no deseamos y estamos desempaquetando item al pasarlo como parámetro del inicializador de Int, al mismo tiempo que desempaquetamos el valor opcional que nos devuelve el inicializador de Int. Al final cuando miramos la línea tenemos tantos signos (||, !, %, =) que si esta fuese un poco más larga ya sería bastante difícil de leer y entender de manera rápida, esto claramente no es legible y es difícil de mantener ya que dada su complejidad puede dar lugar a errores si no llevamos bien en la mente la lógica de cada uno de estos signos dentro de la expresión.

Veamos a continuación lo que a mi entender es una versión mucho más legible y clara:

Sí, ya se que es mucho más largo que el anterior pero te aseguro que es un código mucho más estable, legible y fácil de mantener. Seguimos con el enfoque de salida temprana pero antes nos enfocamos en obtener un valor que podamos manejar con seguridad. Para esto creamos una constante llamada value la cual igualamos con un closure (de la línea 5 a la 11). En este último creamos una constante opcional de tipo Int (línea 7) que igualamos al valor opcional entero que nos devuelve la expresión:

En este inicializador hemos hecho uso del operador de coalescencia nil (??) con el cual declaramos nuestra intención de: si al desempaquetar item este contiene un valor válido se pasa ese valor al inicializador, por el contrario si es nil el valor que pasamos es la cadena “0” ya que recordemos que estamos trabajando con un arreglo de cadenas de texto o String. Con esto nos aseguramos de que si item contiene un valor válido o nil la constante newValue siempre tendrá un valor con el que podremos trabajar.

Nota: Si no entiendes algunos de los conceptos de los que hemos estamos hablando te recomiendo nuestro artículo donde abordamos los valores opcionales y el operador de coalescencia nil al igual que este otro tutorial donde aprenderemos sobre los closures.

Aun así hay una posibilidad de que newValue sea igual a nil y es cuando el valor de item no es nil pero tampoco es válido, es decir cuando el inicializador de Int no puede convertir la cadena String en un valor entero y esto sucedería cuando el valor almacenado en item contiene una letra o un símbolo. Para solucionar esto hacemos una última verificación antes de retornar el valor de newValue (línea 9): usamos nuevamente el operador de coalescencia nil para en el caso de que sea nil retornar 0, de lo contrario su valor actual ya convertido a entero. El closure lo cerramos con paréntesis () para que el código se ejecute y se almacene, el resultado, en la constante value.

Continuamos con la sentencia guard de la línea 13 a la 17, donde verificamos las condiciones que deseamos se cumplan para que nuestro código se ejecute y de no ser así, pues saltamos al siguiente ciclo del bucle. Las condiciones vienen dadas porque sabemos que value puede ser igual a 0 (por lo antes explicado) siendo este el caso, lo descartamos y saltamos al siguiente ciclo ya que no es un número par. En el caso de que sea cualquier otro número pasamos a verificar su paridad, si esto también devuelve un resultado afirmativo quiere decir que ha sido validado y puede ser imprimido en pantalla como un número par.

Si modificamos el array a los siguientes valores:

…la salida en pantalla sería:

Como podemos constatar no hay errores, ni el símbolo de asterisco (*), el valor nil o la letra N pudieron detener la correcta ejecución de nuestro código.

Conclusiones

Como hemos visto en los ejemplos la sentencia guard es muy útil para ciertos casos y como su propio nombre lo indica, algo que ya de por sí ayuda con la legibilidad, su enfoque está en la validación, en servirnos de guardian para que si nuestras condiciones no se cumplen el código dentro de cierta función o bucle jamás se ejecuten. Hemos visto también como se diferencia de “if let” dándonos la posibilidad de acceder a constantes ya desempaquetadas y fuera del ámbito de las llaves. Creo que ha quedado claro que guard e if existen para afrontar situaciones distintas.

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

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 sugerencia, ya sea errores a corregir, información o ejemplos a añadir será, más que bienvenida, necesaria!

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!