O que é um encerramento?
sobes.tech IA
Resposta da IA
O encerramento (closure) em Swift é um bloco autónomo de funcionalidade ({}) que pode ser passado e utilizado no código. Os encerramentos podem capturar e armazenar referências a quaisquer constantes e variáveis do contexto em que são definidos.
Exemplos de uso:
- Como argumentos de funções (por exemplo, manipuladores de conclusão).
- Para definir comportamentos ao enumerar coleções (por exemplo, usando métodos
map,filter,reduce,sorted). - Para executar código de forma diferida.
Sintaxe:
// Sintaxe básica
{ (parâmetros) -> tipoDeRetorno in
declarações
}
// Exemplo de encerramento que aceita um Int e retorna uma String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Número: \(number)"
}
Características:
- Captura automática de variáveis.
- Possibilidade de definir encerramentos sem especificar explicitamente os tipos de parâmetros e o valor de retorno (açúcar sintático).
- Uso de nomes abreviados para os parâmetros ($0, $1, etc.).
- Sintaxe de encerramento com trailing closure.
Captura de variáveis:
Um encerramento pode capturar variáveis do seu ambiente. Por padrão, a captura é feita por referência. Se um encerramento for usado após a variável original ter saído do âmbito, o encerramento ainda mantém acesso a ela.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // Variável do contexto externo
let incrementer: () -> Int = { // Encerramento
runningTotal += amount // Captura runningTotal e amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Saída: 10
print(incrementByTen()) // Saída: 20
Listas de captura (Capture Lists):
São usadas para indicar explicitamente como as variáveis devem ser capturadas - por valor ou por referência, e para evitar ciclos de referências fortes (cycles de retenção).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Captura de self por referência, de value por valor
print("Valor de self.value: \(self.value)")
print("Valor capturado: \(value)")
}
deinit {
print("Instância de MyClass libertada")
}
}
Para evitar ciclos de referências fortes ao capturar objetos de classes, usa-se a sintaxe [weak self] ou [unowned self].
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // Captura fraca de self
guard let self = self else { return } // Verificação da existência de self
// Processamento do resultado
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Operação assíncrona...
}
}