Sobes.tech
Middle

Fale sobre a lista de captura em Swift.

sobes.tech IA

Resposta da IA

A lista de captura em Swift é usada para gerir explicitamente a captura de variáveis por closures. Isto ajuda a evitar ciclos fortes de referências, especialmente ao trabalhar com self em closures usados dentro de classes. Os principais tipos de captura são: weak e unowned.

Tipo de captura Descrição Quando usar
weak Captura a variável como opcional, sem aumentar o contador de referências. O seu valor pode tornar-se nil. Quando o objeto do closure pode sobreviver ao objeto capturado.
unowned Captura a variável sem aumentar o contador de referências, mas assume-se que o objeto capturado viverá enquanto o closure existir. Não é opcional. Quando o objeto do closure e o objeto capturado têm o mesmo tempo de vida, e o objeto capturado não será nil antes do encerramento do closure.

Sintaxe da lista de captura:

{ [lista de captura] (parâmetros) -> tipoDeRetorno in
    // código
}

Exemplo de uso de weak self:

class MyClass {
    var value = 0

    func doSomethingLater() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else { return } // Verificação de nil
            self.value += 1
            print("O valor agora é \(self.value)")
        }
    }
}

Exemplo de uso de unowned self:

class ViewController: UIViewController {
    var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped() {
        // unowned self não é necessário neste caso, pois o botão existe enquanto o ViewController existir.
        // Mas se o closure pudesse sobreviver ao ViewController, unowned poderia ser adequado se
        // tiver a certeza de que self não se tornará nil.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

Pode capturar não só self, mas também quaisquer outras variáveis acessíveis no closure. Por exemplo, para guardar o valor de uma variável no momento da criação do closure:

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Captura initialValue por valor
        currentValue += 1
        print("O valor inicial era \(initialValue)") // initialValue mantém o seu valor
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Output: O valor inicial era 5, depois 6
print(incrementer()) // Output: O valor inicial era 5, depois 7