Swift e Objective-C

Capturas em Swift: variáveis, snapshots e referências

Compare captura de variáveis, listas de captura e referências weak. Guarde um callback escaping e execute-o uma vez depois do registro.

2 min de leitura
Imagem de capa de Capturas em Swift: variáveis, snapshots e referências

Um snapshot na lista de captura não é uma cópia profunda do objeto. Um inteiro preserva o valor da criação da closure; uma referência de classe aponta para o mesmo objeto. weak é outra escolha de propriedade e não mantém o alvo vivo.

Mecanismo e decisão de projeto

Uma closure que captura uma variável local mutável pode observar mudanças posteriores. Uma lista como [number] guarda o valor inicial. Armazenar um parâmetro de closure para uso após o retorno exige @escaping, mas isso não implica assincronia ou vazamento. Fonte primária

Código reproduzível

Em uma função criamos capturas viva e de snapshot e alteramos number para 2. Capturamos uma referência antes de mudar o objeto para 3 e liberamos outro objeto capturado com weak. Queue guarda o callback, executa uma vez e o remove.

Este exemplo independente foi executado em 2026-10-23 com Apple Swift 6.4 para arm64 macOS, no modo de linguagem Swift 6. Não requer rede nem pacotes adicionais.

Baixar o arquivo Swift completo

Execute o comando na pasta do download. As precondições interrompem a execução se uma verificação falhar. Não use -Ounchecked: essa opção remove as verificações.

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()

Saída registrada e interpretação

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

A captura viva retorna 2; o snapshot numérico, 1; e a referência capturada observa 3. weak retorna nil após liberar o alvo. Queue retorna 1 e depois nil. Esta Queue é um exemplo de armazenamento síncrono, não um escalonador assíncrono.

Escopo e limitações

Capturar não implica necessariamente alocar no heap; o compilador pode otimizar o armazenamento. [weak self] não é obrigatório: decida se omitir o trabalho quando o proprietário desaparecer é válido. Investigue caminhos diretos e indiretos de propriedade para confirmar ciclos.

O que verificar em seguida

Documente quem possui callbacks armazenados, quando são removidos e o significado do cancelamento. Não enfraqueça referências automaticamente se a operação precisa manter o proprietário vivo. O experimento ARC demonstra como romper um ciclo real.

Experimento relacionado

Fontes e verificação

  • The Swift Programming Language: ClosuresSwift.org · Documentação oficial · Consultado 23 de outubro de 2026Evidência: Fonte do contrato de implementação e da explicação. A saída foi verificada separadamente com o experimento incluído aqui.