Sobes.tech
Middle

Vždy je potrebné uvádzať parameter `self` v uzávierkach?

sobes.tech AI

Odpoveď od AI

Nie, nie vždy.

Je potrebné jasne uviesť self v uzávierkach iba v nasledujúcich prípadoch:

  1. V ne-unikajúcich (non-escaping) uzávierkach: Ide o požiadavku kompilátora na jasné označenie zachytenia self. Hoci zachytenie technicky existuje, prebieha vo vnútri funkcie a nevytvára cykly silných odkazov.
  2. V unikajúcich (escaping) uzávierkach pri zachytení self implicitne (implicit capture): Ak uzávierka presahuje rámec funkcie, v ktorej bola deklarovaná (napríklad, je odovzdávaná do asynchrónnej operácie, je uložená do vlastnosti atď.), a zachytávate self neexplicitne, kompilátor bude požadovať explicitné uvedenie self pre prehľadnosť potenciálneho cyklu silných odkazov.

Vo všetkých ostatných prípadoch (napríklad, v unikajúcich uzávierkach pri použití zoznamu zachytenia [weak self] alebo [unowned self]) nie je potrebné uvádzať self, pretože vzťah vlastníctva je explicitne riadený.

Príklad:

class MyClass {
    var value = 10

    func doSomething() {
        // Neunikajúca uzávierka - je požadované `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Unikajúca uzávierka s neexplicitným zachytením `self` - je požadované `self`
        // Môže viesť k potenciálnemu cyklu silných odkazov, ak sa nepoužije `[weak self]`
        someAsyncOperation { data, error in
            if let data = data {
                // Vyžaduje `self` pri použití neexplicitného zachytenia
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func bezpečneFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Unikajúca uzávierka s explicitným zachytením `[weak self]` - `self?` je voliteľný a nevyžaduje explicitné `self.` pred volaním
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Rozbalenie `self` ako voliteľného

            if let data = data {
                self.processData(data) // Nie je potrebné `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) {
    // Imaginárna asynchrónna operácia
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}