¿Qué es un cierre?
sobes.tech AI
Respuesta de la IA
El cierre (closure) en Swift es un bloque autónomo de funcionalidad ({}) que puede ser pasado y utilizado en el código. Los cierres pueden capturar y almacenar referencias a cualquier constante y variable del contexto en el que se definen.
Ejemplos de uso:
- Como argumentos de funciones (por ejemplo, manejadores de finalización).
- Para definir comportamientos al enumerar colecciones (por ejemplo, usando métodos
map,filter,reduce,sorted). - Para ejecutar código de forma diferida.
Sintaxis:
// Sintaxis básica
{ (parámetros) -> tipoDeRetorno in
declaraciones
}
// Ejemplo de cierre que recibe un Int y devuelve un String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Número: \(number)"
}
Características:
- Captura automática de variables (capturing values).
- Posibilidad de definir cierres sin especificar explícitamente los tipos de parámetros y el valor de retorno (azúcar sintáctica).
- Uso de nombres abreviados para los parámetros ($0, $1, etc.).
- Sintaxis de cierre con trailing closure.
Captura de variables:
Un cierre puede capturar variables de su entorno. Por defecto, la captura se realiza por referencia. Si un cierre se usa después de que la variable original ha salido del ámbito, el cierre aún mantiene acceso a ella.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // Variable del contexto externo
let incrementer: () -> Int = { // Cierre
runningTotal += amount // Captura runningTotal y amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Salida: 10
print(incrementByTen()) // Salida: 20
Listas de captura (Capture Lists):
Se usan para indicar explícitamente cómo deben ser capturadas las variables, por valor o por referencia, y para evitar ciclos de referencias fuertes (retain cycles).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Captura self por referencia, value por valor
print("Valor de self.value: \(self.value)")
print("Valor capturado: \(value)")
}
deinit {
print("Instancia de MyClass liberada")
}
}
Para evitar ciclos de referencias fuertes al capturar objetos de clases, se usa la sintaxis [weak self] o [unowned self].
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // Captura débil de self
guard let self = self else { return } // Verificación de existencia de self
// Procesamiento de result
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Operación asíncrona...
}
}