Sobes.tech
Middle

Je vždy třeba uvádět parametr `self` v uzávěrkách?

sobes.tech AI

Odpověď od AI

Ne, ne vždy.

Je nutné explicitně uvádět self v uzávěrech pouze v následujících případech:

  1. V ne-unikajících (non-escaping) uzávěrech: Jedná se o požadavek kompilátoru na jasné označení zachycení self. Ačkoliv zachycení technicky existuje, probíhá uvnitř funkce a nevytváří cykly silných odkazů.
  2. V unikajících (escaping) uzávěrech při zachycení self implicitně (implicit capture): Pokud uzávěr přesahuje rámec funkce, ve které byl deklarován (například je předáván do asynchronní operace, je uložen do vlastnosti atd.), a zachytáváte self neexplicitně, kompilátor bude požadovat explicitní uvedení self pro přehlednost potenciálního cyklu silných odkazů.

Ve všech ostatních případech (například v unikajících uzávěrech při použití seznamu zachycení [weak self] nebo [unowned self]) není nutné uvádět self, protože vztah vlastnictví je explicitně řízen.

Příklad:

class MyClass {
    var value = 10

    func doSomething() {
        // Neunikající uzávěr - je požadováno `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Unikající uzávěr s neexplicitním zachycením `self` - je požadováno `self`
        // Může vést k potenciálnímu cyklu silných odkazů, pokud se nepoužije `[weak self]`
        someAsyncOperation { data, error in
            if let data = data {
                // Vyžaduje `self` při použití neexplicitního zachycení
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func safelyFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Unikající uzávěr s explicitním zachycením `[weak self]` - `self?` je volitelný a nevyžaduje explicitní `self.` před voláním
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Rozbalení `self` jako volitelného

            if let data = data {
                self.processData(data) // `self.` není nutné
                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) {
    // Simulace asynchronní operace
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}