Cuando la closure es el último argumento puede escribirse fuera de los paréntesis. Si además es el único argumento, los paréntesis desaparecen:
let cuadrados = numeros.map { $0 * $0 }
print(cuadrados) // [9, 1, 16, 1, 25, 81]
// Múltiples trailing closures (Swift 5.3+)
UIView.animate(withDuration: 0.3) {
vista.alpha = 0
} completion: { _ in
vista.removeFromSuperview()
}
Captura de valores
Las closures capturan las variables del entorno por referencia. Esto les permite acumular estado entre llamadas:
func makeContador() -> () -> Int {
var count = 0
return { count += 1; return count }
}
let c = makeContador()
print(c()) // 1
print(c()) // 2
print(c()) // 3
@escaping y capture list
Una closure que vive más que la función que la recibe se marca con @escaping. Para evitar retain cycles se usa una capture list con [weak self]:
class ViewModel {
var datos: [String] = []
func cargar(completion: @escaping ([String]) -> Void) {
DispatchQueue.global().async {
completion(["a", "b", "c"])
}
}
func inicio() {
cargar { [weak self] items in
self?.datos = items // weak evita retain cycle
}
}
}
@autoclosure: evaluación perezosa
func log(_ msg: @autoclosure () -> String) {
#if DEBUG
print(msg()) // solo se evalúa en modo DEBUG
#endif
}
log("Estado: (calcularEstadoComplejo())")
