Sobes.tech
Middle

Sempre é necessário indicar o parâmetro `self` em closures?

sobes.tech IA

Resposta da IA

Não, nem sempre.

É necessário indicar explicitamente self nos closures apenas nos seguintes casos:

  1. Em closures não escapantes (non-escaping): Isto é uma exigência do compilador para marcar explicitamente a captura de self. Embora tecnicamente haja captura, ela ocorre dentro da função e não leva a ciclos de referências fortes.
  2. Em closures escapantes (escaping) ao capturar self por padrão (captura implícita): Se o closure sai do âmbito da função onde foi declarado (por exemplo, é passado para uma operação assíncrona, guardado numa propriedade, etc.), e você captura self de forma implícita, o compilador exigirá que indique explicitamente self para maior clareza sobre possíveis ciclos de referências fortes.

Em outros casos (por exemplo, em closures escapantes usando a lista de captura [weak self] ou [unowned self]), não é necessário indicar self, pois a relação de propriedade é controlada explicitamente.

Exemplo:

class MyClass {
    var value = 10

    func doSomething() {
        // Closure não escapante - requer `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Closure escapante com captura implícita de `self` - requer `self`
        // Pode levar a um ciclo de referências fortes se `[weak self]` não for usado
        someAsyncOperation { data, error in
            if let data = data {
                // Requer `self` ao usar captura implícita
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func safelyFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Closure escapante com captura explícita `[weak self]` - `self?` é opcional e não requer `self.` explícito
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Desembrulhar `self` opcional

            if let data = data {
                self.processData(data) // Não é necessário `self.`
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    private func processData(_ data: String) {
        print("Processing \(data)")
    }
}

func someAsyncOperation(completion: @escaping (String?, Error?) -> Void) {
    // Simulação de operação assíncrona
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}