Swift y Objective-C

Capturas en Swift: variables, instantáneas y referencias

Compara capturas de variables, listas de captura y referencias weak. Guarda un callback escaping y ejecútalo una sola vez después de registrarlo.

2 min de lectura
Imagen de portada de Capturas en Swift: variables, instantáneas y referencias

Una instantánea en la lista de captura no es una copia profunda del objeto. Un entero conserva su valor al crear la clausura; una referencia de clase apunta al mismo objeto. weak es otra decisión de propiedad y no mantiene vivo el destino.

Mecanismo y decisión de diseño

Una clausura que captura una variable local mutable puede observar cambios posteriores. Una lista como [number] conserva el valor inicial. Guardar un parámetro de clausura para usarlo tras retornar requiere @escaping, pero no implica asincronía ni fuga de memoria. Fuente primaria

Código reproducible

En una función creamos capturas viva y de instantánea, y cambiamos number a 2. Capturamos una referencia antes de cambiar el objeto a 3 y liberamos otro objeto capturado con weak. Queue guarda el callback, lo ejecuta una vez y lo borra.

Este ejemplo independiente se ejecutó el 2026-10-23 con Apple Swift 6.4 para arm64 macOS, en modo de lenguaje Swift 6. No necesita red ni paquetes adicionales.

Descargar el archivo Swift completo

Ejecuta el comando en la carpeta de descarga. Las precondiciones detienen la ejecución si falla una comprobación. No uses -Ounchecked: elimina estas comprobaciones.

swift -swift-version 6 swift-closure-capture-weak-self-escaping.swift
final class Box { var value = 1 }
final class Queue {
    private var action: (() -> Int)?
    func enqueue(_ action: @escaping () -> Int) { self.action = action }
    func run() -> Int? {
        let current = action
        action = nil
        return current?()
    }
}

func experiment() {
    var number = 1
    let live = { number }
    let snapshot = { [number] in number }
    number = 2
    precondition(live() == 2 && snapshot() == 1)

    let box = Box()
    let capturedReference = { [box] in box.value }
    box.value = 3
    precondition(capturedReference() == 3)

    var temporary: Box? = Box()
    let weakRead = { [weak box = temporary] in box?.value }
    precondition(weakRead() == 1)
    temporary = nil
    precondition(weakRead() == nil)

    let queue = Queue()
    queue.enqueue(snapshot)
    precondition(queue.run() == 1 && queue.run() == nil)
    print("variable=2 snapshot=1 captured-object=3 weak-after-release=nil queued=1 then=nil")
}
experiment()

Salida registrada e interpretación

variable=2 snapshot=1 captured-object=3 weak-after-release=nil queued=1 then=nil

La captura viva devuelve 2; la instantánea numérica, 1; y la referencia capturada observa 3. weak devuelve nil tras liberar el objeto. Queue devuelve 1 y luego nil. Esta Queue ilustra almacenamiento síncrono, no es un planificador asíncrono.

Alcance y limitaciones

Capturar no implica necesariamente asignar memoria en el heap; el compilador puede optimizarla. [weak self] no es obligatorio: decide si omitir el trabajo al desaparecer el propietario es válido. Investiga rutas de propiedad directas e indirectas para confirmar un ciclo.

Qué comprobar después

Documenta quién posee los callbacks guardados, cuándo se borran y qué significa cancelarlos. No debilites referencias automáticamente si la operación necesita mantener vivo al propietario. El experimento ARC demuestra cómo romper un ciclo real.

Experimento relacionado

Fuentes y verificación

  • The Swift Programming Language: ClosuresSwift.org · Documentación oficial · Consultado 23 de octubre de 2026Respalda: Fuente del contrato de implementación y de la explicación. La salida se comprobó por separado con el experimento incluido aquí.