Lição: 33: Fechamentos Avançados (Capturando Valores)
No Swift, fechamentos são blocos de funcionalidade autocontidos que podem ser passados e utilizados no seu código. Uma das características poderosas dos fechamentos é a sua capacidade de capturar e armazenar referências a variáveis e constantes do contexto ao seu redor onde foram definidos. Esse comportamento é conhecido como captura de valores.
Nesta aula, vamos explorar o conceito de captura de valores em fechamentos, como isso funciona e suas aplicações práticas.
Compreendendo a Captura de Valores
Quando você cria um fechamento, ele pode capturar e armazenar referências a variáveis e constantes de seu contexto envolvente. Isso significa que, mesmo que essas variáveis saiam do escopo, o fechamento mantém suas próprias cópias dessas variáveis.
Aqui está um exemplo simples para ilustrar isso:
func criaIncrementador(quantidadeIncremento: Int) -> () -> Int {
var total = 0
// O fechamento captura a variável `total` e `quantidadeIncremento`
let incrementador: () -> Int = {
total += quantidadeIncremento
return total
}
return incrementador
}
let incrementaPorDois = criaIncrementador(quantidadeIncremento: 2)
print(incrementaPorDois()) // Saída: 2
print(incrementaPorDois()) // Saída: 4
print(incrementaPorDois()) // Saída: 6
Nesse exemplo, a função criaIncrementador
retorna um fechamento que incrementa uma variável total
por uma quantidadeIncremento
especificada. Mesmo após a execução da função criaIncrementador
, o fechamento incrementador
mantém uma referência a total
e quantidadeIncremento
. Cada vez que chamamos incrementaPorDois
, ele atualiza e retorna o total.
Capturando Valores em Tipos de Referência
Os fechamentos também podem capturar tipos de referência, como classes. Ao capturar um tipo de referência, o fechamento mantém uma referência forte ao objeto, o que pode levar a ciclos de retenção se não for gerenciado corretamente.
Aqui está um exemplo com uma classe:
class Contador {
var contagem = 0
lazy var incrementador: () -> Int = {
self.contagem += 1
return self.contagem
}
}
let contador = Contador()
print(contador.incrementador()) // Saída: 1
print(contador.incrementador()) // Saída: 2
print(contador.incrementador()) // Saída: 3
Neste caso, a classe Contador
possui uma propriedade lazy
chamada incrementador
que captura self
, permitindo que incrementemos a propriedade contagem
. O fechamento captura self
de forma forte, o que normalmente é seguro neste contexto, mas requer um cuidado especial em cenários mais complexos para evitar vazamentos de memória.
Capturando Valores e Fechamentos Escapáveis
Quando um fechamento é definido como escapável, isso significa que o fechamento pode sobreviver ao escopo da função na qual foi passado, potencialmente levando a situações onde os valores capturados precisam ser gerenciados com cuidado.
Aqui está um exemplo usando um fechamento escapável:
var manipuladorDeConclusao: (() -> Void)?
func fazAlgoAssíncrono(conclusao: @escaping () -> Void) {
manipuladorDeConclusao = conclusao
}
fazAlgoAssíncrono {
print("Operação assíncrona concluída!")
}
// Chame o manipulador de conclusão mais tarde
manipuladorDeConclusao?()
Neste exemplo, fazAlgoAssíncrono
aceita um fechamento escapável como parâmetro, permitindo que o armazenemos em manipuladorDeConclusao
. O fechamento captura o contexto ao seu redor, e podemos invocá-lo mais tarde quando a tarefa assíncrona for concluída.
Conclusão
A captura de valores é um recurso fundamental dos fechamentos em Swift que permite poderosas abstrações e encapsulamentos no seu código. Compreender como os fechamentos capturam variáveis e constantes do seu contexto é crucial para escrever um código Swift eficaz.
À medida que você trabalha mais com fechamentos, tenha em mente as implicações da captura de valores, especialmente em contextos onde tipos de referência estão envolvidos, e ao lidar com fechamentos escapáveis para evitar problemas de gerenciamento de memória. Experimente os exemplos fornecidos para se familiarizar com esses conceitos, e você se tornará mais confortável usando fechamentos em suas aplicações Swift.