¿Qué es un Closure?
Libranner Santos
19 marzo, 20234min de lectura
Closure es uno de los principales rompecabezas para los desarrolladores cuando comienzan a usar Swift. Estos no son más que bloques de código. Estos bloques los podemos pasar en nuestro código y usarlos según convenga. Un caso muy común, es pasar closures para ejecutar al final de funciones asíncronas.
¿Cómo declarar un Closure?
let myClosure = (String) -> Int
En este caso indicamos que:
- El nombre de nuestro closure,
myClosure
. - La estructura del closure consiste primero en indicar entre paréntesis los tipos de valores que aceptaremos, en este caso, solo recibiremos un
String
. Podemos indicar separado por coma, tantos parámetros como necesitemos. - Por último, luego del arrow
->
, indicamos el tipo de dato de retorno, en este caso,Int
. Si no quisiéramos que retorne algún valor, podríamos ponerVoid
(o también podemos poner dos paréntesis sin ningún tipo()
).
Tip: Es importante saber, que los closures son variables por referencia, no por valor.
Sintaxis de un Closure
En resumen, esta es la sintaxis de un closure:
{ (parámetros) -> tipo-de-retorno incódigo}
Trailing Closures
Trailing closures son una forma alternativa de pasar un closure a una función que acepta el mismo, la única condición es que este debe estar al final de la función.
Por ejemplo, si tenemos la siguiente función:
func execute(completion: (Int) -> Void) {// ....}
Podemos llamarla de la siguiente manera:
execute { value in}
Colocamos el nombre de la función y seguido escribimos nuestro closure. Note el código value in
esto indica que vamos a captura el valor Int
que requerimos en nuestro closure en la variable value
. Mientras que in
es una palabra reservada que colocamos al final de nuestros parámetros.
Tip: Si por alguna razón no necesitáramos almacenar el valor, en vez de
value in
escribiríamos_ in
. Esto le hace saber al compilador que no queremos almacenar esos datos, así optimizamos el uso de memoria.
Inferencia y Closures
El compilador hace muchas cosas para hacer tu vida más sencilla. Cuando trabajas con closures, puedes hacer uso de la inferencia para escribir menos código.
Inferencia de parámetros
En vez de indicar nombres para tus parámetros, puedes usar la notación $#
, donde #
es el numero indica la posición del parámetro (empezando por cero). Por ejemplo:
let array = [1, 2, 3]let result = array.map { value inreturn value + 1}
Este código hace uno de .map
para recorrer los valores de array
y sumarle uno a cada uno, para grabar los siguientes valores en result
, [2, 3, 4].
El siguiente código obtendría el mismo resultado:
let array = [1, 2, 3]let result = array.map { $0 + 1 }
En este caso usamos la sintaxis abreviada $0
. Esto nos da los siguientes beneficios:
- No tenemos que nombrar la variable, al usar
$0
Swift infiere que necesitamos el primer valor de la lista de parámetros disponible, en este caso, hay solo uno. - No necesitamos usar la palabra reservada
in
, - No necesitamos usar la palabra return, ya que nuestro código solo requiere una línea.
Escaping
Imagina que tienes una función que hace una solicitud a un servidor y quieres imprimir el resultado de la misma. Como no sabes cuando esa solicitud terminará, utilizas un closure y le indicas que debe ser ejecutado cuando recibas la respuesta.
A continuación un ejemplo donde llamamos una función que acepta un closure con @escaping
:
func getData(completion: @escaping (String) -> Void) {DispatchQueue.main.asyncAfter(deadline: .now() + 2) {completion("data")}print("Returned")}
Esta función simula un tiempo de espera de dos segundos usando DispatchQueue.main.asyncAfter(deadline: .now() + 2)
. Y luego imprime el texto Returned. Sin embargo, luego de pasado dos segundos, llama nuestro closure, el cual como usa @escaping
lo que le permite ejecutarse incluso luego de que la función getData(completion:)
ha retornado.
Hasta aquí los fundamentos básicos para poder utilizar y entender los closures. Ten en cuenta que, aunque los closures pueden ser herramientas muy útiles y versátiles, debemos tener cuidado ya que el uso abusivo de los mismos puede hacer que nuestro código sea difícil de entender.