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:
- In niet-escapende (non-escaping) closures: Dit is een vereiste van de compiler om expliciet de capture van
selfaan te geven. Hoewel er technisch gezien een capture is, gebeurt deze binnen de functie en leidt niet tot sterke referentiecirkels. - 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.) enselfimpliciet wordt vastgelegd, vereist de compiler dat je explicietselfaangeeft 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)
}
}