ProgrammierungiOS Entwickler

Was sind escaping und non-escaping Closures in Swift? Wie organisiert man richtig die Arbeit mit Closures, welche Nuancen gibt es in ihrer Verwendung und welche Schwierigkeiten können bei der Arbeit mit asynchronem Code auftreten?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Escaping Closure ist ein Closure, das "aus der Sichtbarkeit" der aufrufenden Funktion "entkommt" (z. B. für asynchrone Ausführung gespeichert wird).

Standardmäßig akzeptieren Funktionen in Swift non-escaping Closures: Das Closure wird innerhalb des Funktionsaufrufs ausgeführt.

Um ein escaping ausdrücklich anzugeben, wird das Schlüsselwort @escaping verwendet:

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

Wesentliche Unterschiede:

  • Escaping Closures können gespeichert und später aufgerufen werden.
  • Um self in einem escaping Closure zu erfassen, muss man [weak self] oder [unowned self] ausdrücklich angeben, um Speicherlecks (retain cycles) zu vermeiden.

Trickfrage.

Muss man immer @escaping für Closures verwenden, die als Parameter in Funktionen übergeben werden, die DispatchQueue.async aufrufen?

— Ja. Da DispatchQueue.async das Closure bis zur Ausführung speichert, wird das Closure escaping.

Beispiel:

func foo(action: () -> Void) { DispatchQueue.main.async { action() // Kompiliert nicht: Closure muss escaping sein. } } // Muss: func bar(action: @escaping () -> Void) { ... }

Beispiele für reale Fehler aufgrund fehlenden Wissens über die Nuancen des Themas.


Geschichte

Der Controller hat eine starke Referenz auf self innerhalb eines escaping Closures erstellt (z. B. bei einer Netzwerkanfrage). Der Controller wurde nicht freigegeben, nachdem er vom Bildschirm verschwunden war — starker retain cycle. Lösung: Verwenden von [weak self] oder [unowned self].


Geschichte

Die Funktion übergab das Closure an DispatchQueue.async, jedoch wurde es nicht als escaping markiert. Das Projekt wurde nicht kompiliert, die Fehler waren aufgrund der Verschachtelung der Funktionen schwer zu finden.


Geschichte

Innerhalb des Closures wurde auf ein Objekt zugegriffen, das zum Zeitpunkt des Aufrufs des Closures bereits deinitialisiert war (verwendeten [unowned self]). In der Folge — Laufzeitfehler. Lösung: Verwenden von [weak self] und Überprüfung auf nil.