Sobes.tech
Middle

Muss man in Closures immer den Parameter `self` angeben?

sobes.tech KI

Antwort von AI

Nein, nicht immer.

Es ist notwendig, self in Closures nur in den folgenden Fällen explizit anzugeben:

  1. Bei nicht-escapenden (non-escaping) Closures: Dies ist eine Anforderung des Compilers, um die Capture von self explizit zu kennzeichnen. Obwohl technisch eine Capture stattfindet, geschieht diese innerhalb der Funktion und führt nicht zu starken Referenzzyklen.
  2. Bei escapenden (escaping) Closures, bei denen self standardmäßig (implizit) erfasst wird: Wenn das Closure den Gültigkeitsbereich der Funktion verlässt, in der es deklariert wurde (z.B. bei Übergabe an eine asynchrone Operation, Speicherung in einer Eigenschaft usw.), und self implizit erfasst wird, verlangt der Compiler eine explizite Angabe von self zur Klarstellung möglicher starker Referenzzyklen.

In anderen Fällen (z.B. bei escapenden Closures mit der Capture-Liste [weak self] oder [unowned self]) ist die Angabe von self nicht erforderlich, da die Besitzverhältnisse explizit kontrolliert werden.

Beispiel:

class MyClass {
    var value = 10

    func doSomething() {
        // Nicht-escapendes Closure - erfordert `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Escapendes Closure mit impliziter `self`-Erfassung - erfordert `self`
        // Kann zu einem starken Referenzzyklus führen, wenn `[weak self]` nicht verwendet wird
        someAsyncOperation { data, error in
            if let data = data {
                // Erfordert `self` bei Verwendung der impliziten Erfassung
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func safelyFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Escapendes Closure mit expliziter Capture-Liste `[weak self]` - `self?` ist optional und erfordert kein explizites `self.`
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // `self` optional entpacken

            if let data = data {
                self.processData(data) // Kein `self.` erforderlich
                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) {
    // Simulation einer asynchronen Operation
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}