Sobes.tech
Junior

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...
    }
}