ProgrammatieiOS ontwikkelaar

Wat zijn escaping en non-escaping closures in Swift? Hoe organiseer je het gebruik van closures correct, welke nuances zijn er bij hun gebruik en welke problemen kunnen zich voordoen bij het werken met asynchrone code?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Escaping closure is een closure die "wegglijdt" uit de scope van de aanroepende functie (bijvoorbeeld, het wordt opgeslagen voor asynchrone uitvoering).

Standaard accepteren functies in Swift non-escaping closures: de closure wordt uitgevoerd binnen de aanroep van de functie.

Om expliciet aan te geven dat een closure escaping is, wordt het sleutelwoord @escaping gebruikt:

func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }

Belangrijke verschillen:

  • Escaping closures kunnen worden opgeslagen en later worden aangeroepen.
  • Om self vast te leggen in een escaping closure, moet je expliciet [weak self] of [unowned self] aangeven om geheugenlekken (retain cycle) te voorkomen.

Misleidende vraag.

Moet je altijd @escaping schrijven voor closures die worden doorgegeven als parameters van de functierit DispatchQueue.async?

— Ja. Omdat DispatchQueue.async de closure opslaat tot het moment van uitvoering, wordt de closure escaping.

Voorbeeld:

func foo(action: () -> Void) { DispatchQueue.main.async { action() // Compileert niet: closure moet escaping zijn. } } // Nodig: func bar(action: @escaping () -> Void) { ... }

Voorbeelden van echte fouten door onwetendheid over de nuances van het onderwerp.


Verhaal

De controller maakte een sterke referentie naar self binnen een escaping closure (bijvoorbeeld een netwerkverzoek). De controller werd niet vrijgegeven na vertrek van het scherm — sterke retain cycle. Oplossing: gebruik [weak self] of [unowned self].


Verhaal

De functie gaf een closure door aan DispatchQueue.async, maar merkte deze niet aan als escaping. Het project compileerde niet, fouten waren moeilijk te vinden door de geneste functies.


Verhaal

Binnen de closure werd verwezen naar een object dat al was gedeïnitieerd op het moment van aanroepen van de closure (gebruikte [unowned self]). Resultaat — runtime crash. Oplossing: gebruik [weak self] en controleer op nil.