Sobes.tech
Middle

Moet je in closures altijd de parameter `self` aangeven?

sobes.tech AI

Antwoord van AI

Nee, niet altijd.

Het is nodig om self expliciet aan te geven in closures alleen in de volgende gevallen:

  1. In niet-escapende (non-escaping) closures: Dit is een vereiste van de compiler om expliciet de capture van self aan te geven. Hoewel er technisch gezien een capture is, gebeurt deze binnen de functie en leidt niet tot sterke referentiecirkels.
  2. In escapende (escaping) closures, bij standaard (impliciete) capture van self: Als de closure buiten het bereik van de functie waarin deze is gedeclareerd treedt (bijvoorbeeld, wordt doorgegeven aan een asynchrone operatie, opgeslagen in een eigenschap, etc.) en self impliciet wordt vastgelegd, vereist de compiler dat je expliciet self aangeeft voor duidelijkheid over mogelijke sterke referentiecirkels.

In andere gevallen (bijvoorbeeld, in escapende closures met gebruik van de capture-lijst [weak self] of [unowned self]) is het niet nodig om self aan te geven, omdat de eigendomsrelatie expliciet wordt gecontroleerd.

Voorbeeld:

class MyClass {
    var value = 10

    func doSomething() {
        // Niet-escapende closure - vereist `self`
        UIView.animate(withDuration: 0.3) {
            self.value = 20
        }
    }

    func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
        // Escapende closure met impliciete capture van `self` - vereist `self`
        // Kan leiden tot een sterke referentiecircuit als `[weak self]` niet wordt gebruikt
        someAsyncOperation { data, error in
            if let data = data {
                // `self` is vereist bij gebruik van impliciete capture
                self.processData(data)
                completion(.success("Data processed"))
            } else if let error = error {
                completion(.failure(error))
            }
        }
    }

    func safelyFetchData(completion: @escaping (Result<String, Error>) -> Void) {
         // Escapende closure met expliciete capture `[weak self]` - `self?` is optioneel en vereist geen expliciet `self.`
        someAsyncOperation { [weak self] data, error in
            guard let self = self else { return } // Unwrappen van `self` optioneel

            if let data = data {
                self.processData(data) // Geen `self.` nodig
                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) {
    // Simulatie van een asynchrone operatie
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion("Some data", nil)
    }
}