Completion Handler und Escaping

Tolga Sarikaya
3 min readDec 2, 2023

--

Completion Handler

Es handelt sich um einen Closure, der nach Abschluss einer Operation ausgeführt wird. Es wird insbesondere bei asynchronen Vorgängen wie Netzwerkanfragen oder Datei-Lese-/Schreibvorgängen verwendet. Nach Abschluss einer Operation oder dem Beenden einer Funktion wird der Closure (Abschlussfunktion) aufgerufen und kann verwendet werden, um das Ergebnis der Operation oder den Fehlerzustand zu behandeln.

// Eine Funktion, die einen Completion Handler verwendet
func doCalculation(number: Int, completion: (Int) -> Void) {

// Berechnung durchführen
let result = number * 2

// Das Ergebnis über den Completion Handler zurückgeben
completion(result)
}

// Die Funktion aufrufen und den Completion Handler verwenden
print("Berechnung gestartet.")
doCalculation(number: 5) { result in
print("Das Ergebnis der Berechnung ist: \(result)")

In diesem Beispiel führt eine Funktion namens ‘doCalculation’ eine Berechnung durch, um das Doppelte einer Zahl zu finden. Wenn die Funktion aufgerufen wird, wird eine Zahl übergeben und das Doppelte dieser Zahl wird berechnet. Sobald die Berechnung abgeschlossen ist, wird der Completion Handler verwendet, um das Ergebnis der Berechnung zurückzugeben und auf dem Bildschirm auszugeben.

Um zu verstehen was escaping ist , mussten wir erst Completion Handler verstehen.

Escaping

Es wird verwendet um anzuzeigen, dass eine Closure auch nach Verlassen des Bereichs einer Funktion aufgerufen werden kann.

Closures werden normalerweise innerhalb von Funktionen definiert und sollten standardmäßig innerhalb des Bereichs der Funktion ausgeführt werden. Allerdings müssen Closures in manchen Fällen auch außerhalb des Funktionsbereichs aufgerufen werden können. Hier kommt ‘@escaping’ ins Spiel.

Zum Beispiel, wenn eine Funktion einen asynchronen Vorgang startet und nach Abschluss dieses Vorgangs eine Closure aufgerufen wird, muss diese Closure als ‘@escaping’ gekennzeichnet sein. In diesem Fall kann die Closure auch nach Abschluss der Funktion noch aufgerufen werden.”

class AsyncCalculator {

func doCalculation(number: Int, completion: @escaping (Int) -> Void) {
DispatchQueue.global().async { [weak self] in
// Eine aufwändige Berechnung durchführen
let result = number * 2

// Das Ergebnis über den Completion Handler zurückgeben
completion(result)

// Beispiel: Auf self zugreifen, um andere Methoden aufzurufen
self?.handleCompletion()
}
}

func handleCompletion() {
print("Berechnung abgeschlossen.")
}
}

// Die Klasse verwenden und den Completion Handler mit 'self' verwenden
let asyncCalc = AsyncCalculator()
print("Berechnung gestartet.")
asyncCalc.doCalculation(number: 5) { result in
print("Das Ergebnis der Berechnung ist: \(result)")
}

Dieses Beispiel erstellt eine Klasse namens AsyncCalculator. Diese Klasse verfügt über eine Methode namens ‘doCalculation’. Diese Methode startet eine asynchrone Aufgabe und gibt das Ergebnis mithilfe eines ‘@escaping’ Closures zurück.

Durch die Verwendung von [weak self] innerhalb des Closures verhindern wir eine starke Referenz cycle. Dadurch verwenden wir anstelle einer starken Referenz auf die Klasse eine schwache Referenz, wenn wir ‘self’ verwenden.

Wenn die Aufgabe in der Methode doCalculation abgeschlossen ist, wird das Completion-Closure aufgerufen und das Ergebnis zurückgegeben. Außerdem wird nach Abschluss der Aufgabe eine andere Methode namens ‘handleCompletion’ aufgerufen.

Warum müssen wir [weak self] verwenden?

Referenzen auf Klassen oder Strukturen, die in einer Closure verwendet werden, müssen auch beim Ausführen der Closure noch gültig sein. Wenn wir kein ‘self’ verwenden und versuchen, innerhalb der Closure auf Elemente der Klasse zuzugreifen, wird uns der Compiler einen Fehler anzeigen, der darauf hinweist, dass die Referenz stark erfasst werden muss und Dies wird verwendet, um Speicherlecks oder zyklische Abhängigkeiten zu vermeiden.

In diesem Fall verwenden wir ‘self’, damit wir auch sicher auf die Elemente der Klasse zugreifen können, selbst wenn die Closure aus dem äußeren Bereich aufgerufen wird. Dennoch können Methoden wie [weak self] oder [unowned self] verwendet werden, um eine starke Referenz cycle zu verhindern.

@escaping Closures werden oft bei asynchronen Operationen oder in Situationen verwendet, in denen Closures, die von einer Funktion zurückgegeben werden, eine längere Lebensdauer haben. In solchen Fällen ist die Verwendung von ‘self’ wichtig, um sicher auf Klassenelemente innerhalb der Closure zuzugreifen. Dadurch können die Elemente der Klasse sicher während der Ausführung der Closure verwendet werden.

In meinem Artikel wollte ich Ihnen kurz etwas über Completion Handler und Escaping erzählen, ich hoffe, es war nützlich.

--

--