0Pricing
Swift Academy · Lección

Clausuras

Clausuras

Clausuras es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 1 de 1. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 1 lecciones en total.

Introducción

Hola:

Los closures son bloques de código independientes. Un closure se pasa como parámetro al código o puede utilizarse dentro de él.

Un closure es un tipo de función. Puede utilizarse pasándolo dentro del código. Son similares a las lambdas de otros lenguajes de programación.

Gestión de memoria

Uno de los aspectos más importantes es que un closure puede capturar y almacenar los valores de las constantes y variables del contexto en el que se define.

Este almacenamiento se conoce como closing-over.

Swift gestiona la memoria por nosotros durante este almacenamiento.

Tipos de closure

Existen varios tipos de closure.

  1. Las funciones globales son closures con nombre y no conservan ningún valor.
  2. Las funciones anidadas pueden conservar los valores del nombre y de la función que las envuelve.
  3. Las expresiones de closure, por su parte, son closures anónimos y pueden almacenar datos del contexto que las rodea mediante una sintaxis sencilla.

Sintaxis de los closures

Se intenta simplificar la sintaxis de los closures tanto como sea posible. Los aspectos más importantes son los siguientes.

  • Los parámetros de los closures pueden inferirse.
  • Los valores de retorno pueden inferirse.
  • Un closure puede devolver un valor en una sola línea.
  • Los nombres de los argumentos pueden expresarse mediante abreviaturas como $ 0 o $ 1.
  • Se puede utilizar la sintaxis de trailing closure.

Información

Las expresiones de closure consisten en escribir los closures en línea, priorizando la sintaxis y la simplicidad.

Sintaxis de un closure

A continuación se muestra la sintaxis de un closure en el código de ejemplo.

{ (parameters) -> return type in
    statements
}


func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.

var reversedNames = names.sorted(by: backward)

Sintaxis de un closure

Sin embargo, al utilizar un closure no necesitamos definir un closure global con nombre innecesario de este tipo.

Basta con definir una expresión de closure sencilla como parámetro. Veamos el ejemplo.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

///sorted method takes closure as parameter.

Palabra clave in

La palabra clave in indica que comienza el cuerpo del closure.

Antes de la palabra clave in deben definirse los parámetros que recibe el closure y el tipo de retorno.

Inferencia de tipos a partir del contexto

Inferencia de tipos a partir del contexto

En el ejemplo anterior, la expresión de closure puede entenderse mediante la inferencia de los parámetros y del tipo de retorno, ya que el método sorted recibe un closure.

Por lo tanto, no es necesario definirlos explícitamente.

En este ejemplo, se entenderá que, como los valores del array names son Strings, los parámetros que recibe el closure serán de tipo String.

Del mismo modo, como el closure correspondiente necesita un tipo Bool para ordenar, el tipo de retorno se inferirá como Bool.

Ejemplo

Esto simplifica el uso de la siguiente manera.

La flecha también puede omitirse del código al inferir el tipo de retorno.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

Sintaxis abreviada

Es preferible utilizar la sintaxis larga en lugar de la abreviada para no confundir a quienes leen el código.

La sintaxis anterior puede abreviarse aún más.

El valor de retorno puede abreviarse en la expresión de closure eliminando la palabra clave return.

/*
In this example, the return keyword has been extracted.
It already has single expression. 
There is no need to express it as an extra with return.
*/

var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)

Ejemplo

En este ejemplo se ha omitido la palabra clave return.

Ya hay una sola expresión, por lo que no es necesario indicarla explícitamente mediante return.

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

Abreviatura de nombres

La sintaxis puede abreviarse aún más. En el ejemplo anterior indicamos que el closure recibe dos parámetros, incluidos s1 y s2. Sus tipos se infieren.

Ahora podemos evitar expresar estos parámetros mediante abreviaturas y definirlos por separado.

Además, como no hay una definición de parámetros ni un valor de retorno explícito, también se puede omitir la palabra clave in.

let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)

// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.

Ejemplo abreviado

var names = ["Coddy", "Kit"]

let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.

TRAILING CLOSURE

Trailing Closure

Si el closure que se pasa a una función es el argumento final de esta y la expresión de closure es larga, puede resultar más útil escribirla mediante la sintaxis de trailing closure.

Podemos utilizar trailing closure como una forma abreviada de la sintaxis. Se utiliza para aumentar la legibilidad del código.

El último parámetro de la mayoría de los métodos de iOS es un closure.

Parámetro final

Por ejemplo, en este caso, el parámetro final es un closure.

class Animator {
    class func animate(withDuration duration: Double, animations: () -> Void) {
        animations()
    }
}

class MyViewController {
    func start() {
        // With the traditional method, we can call this fund as follows.
        Animator.animate(withDuration: 1, animations: { [unowned self] in
            print("red")
        })
    }
}
MyViewController().start()

Como el código anterior es menos legible, puede escribirse de la siguiente manera

Como el código anterior es menos legible, puede escribirse de la siguiente manera.

import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")

Ejemplo

Al utilizar la sintaxis de trailing closure, no es necesario escribir la etiqueta del argumento.

Esto se debe a que los closures ahora forman parte de la llamada a la función.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

Sintaxis

En realidad, podemos considerar la sintaxis de trailing closure como una forma abreviada de la sintaxis. Hace que el código sea más legible.

/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)

// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
    self.view.backgroundColor = UIColor.red
})

/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method 
is closure, Swift allows to make a call like the one below.
*/

UIView.animate(withDuration: 1) { [unowned self] in
    self.view.backgroundColor = UIColor.red
}

Podemos utilizar el código siguiente para probar el código

Podemos utilizar el código siguiente para probar el código.


func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}

greetThenRunClosure(name: "Paul") {
    print("The closure was run")
}

Captura de valores por closures

Captura de valores por closures

Un closure puede capturar los valores de las variables del entorno que lo engloba. Incluso es posible cambiar el valor de estas variables desde el propio cuerpo del closure y acceder a ellas.

Aunque estas variables ya no se encuentren en el ámbito original en el que se definieron.

Continuación

En general, estos datos pueden conservarse en funciones anidadas junto con expresiones de closure. Estas pueden almacenar los datos de la función externa.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)

print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30

Continuación

Si asigna un closure como propiedad de una clase, este comenzará a mantener una referencia a la instancia que lo contiene.

Por lo tanto, se establecerá un ciclo de referencias fuertes entre el closure y la instancia.

Se debe prestar especial atención a las fugas de memoria.

Advertencia

Los closures y las funciones son tipos de referencia.

@escaping

Este uso puede ser necesario en muchos casos en los que el closure se utiliza de forma asíncrona.

En las primeras versiones de Swift (1 y 2), los closures de los parámetros de Swift eran escapables y después pasaron a ser no escapables. Si necesitábamos pasar un closure no escapable, teníamos que especificarlo explícitamente.

En las versiones posteriores, los parámetros closure se hicieron no escapables para obtener una ventaja en cuanto al uso de memoria.

Ahora, si queremos definir un closure escapable, debemos especificarlo mediante la palabra clave @escaping.

Palabra clave @ESCAPING

Palabra clave @ESCAPING

Si queremos poder llamar a los closures asignados a una función después de que esta devuelva el control, debemos utilizar la palabra clave @escaping.

Los closures definidos como parámetros de una función son tipos de referencia, pero no incrementan el recuento de referencias. Esto se debe a que, al realizar la llamada, finaliza la vida útil de este closure y no es necesario aumentar el recuento de referencias.

Sin embargo, si necesitamos utilizar como parámetro un closure después de llamar a una función, puede ser necesario expresarlo mediante la palabra clave @escaping.

nonEscaping

Primero, veamos cómo funciona un closure no escapable.

Cuando este closure se pasa como parámetro a la función, se procesa en el cuerpo de la función y luego se devuelve al compilador.

Después de que la función devuelve el control, es decir, una vez completada la ejecución, el closure queda fuera de su ámbito y se libera de la memoria.

Uso de un closure escapable

Uso de un closure escapable

Cuando una función closure se pasa como argumento, continúa conservándose incluso después de que la función devuelva el control y finalice la ejecución.

Además, ocupa espacio en la memoria hasta que se ejecuta el closure. Existen varios tipos de closures escapables.

Enhorabuena

Enhorabuena 🎉

Hemos llegado al final de nuestra lección. 

Nos vemos en la próxima lección 😎

Clausuras — ilustración 29

Preguntas frecuentes

¿La lección «Clausuras» es gratis?

Sí — el texto completo de «Clausuras» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 1 lecciones en total.

¿Qué aprenderé en «Clausuras»?

Clausuras Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 1.

¿Cuánto tiempo toma la lección «Clausuras»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

← Volver a Swift Academy