async/await-Basics
Die kommende Version 5.5 von Swift ist Teil von Xcode 13 und wird eine große Neuerung in der Programmiersprache mit sich bringen. Mithilfe der neuen Schlüsselwörter async
und await
lassen sich nun endlich asynchrone Befehle ausführen, ohne auf entsprechende Funktionen des Dispatch-Frameworks zurückgreifen zu müssen.
Das Grundprinzip hinter den neuen Swift-Schlüsselwörtern async
und await
ist denkbar simpel. Mit async
kann man Funktionen deklarieren und so festlegen, dass diese asynchron ablaufen. Während die Funktion also ihre Befehle abarbeitet, kann die zugrundeliegende App von anderer Stelle weitere Befehle entgegennehmen und ausführen.
Möchte man eine mittels async
deklarierte Funktion nutzen, muss man bei ihrem Aufruf das await
-Keyword setzen. Dieses Pattern ist vergleichbar mit dem Error Handling in Swift, in dem Funktionen mit throws
und zugehörige Aufrufe mit try
gekennzeichnet werden.
Gelangt die Programmausführung an den Aufruf einer asynchronen Funktion mittels await
, wird die Ausführung an dieser Stelle „angehalten“. Die App kann zwar weiterhin Befehle von anderer Stelle verarbeiten, doch alle Aufrufe, die nach await
folgen, werden erst ausgeführt, wenn die darüber asynchron aufgerufene Funktion abgeschlossen ist.
Ein einfaches Beispiel zum Einsatz von async
und await
demonstriert das folgende (noch nicht optimierte) Beispiel. Darin wird über einen Button eine aufwendige Berechnung aufgerufen. Noch läuft der Code synchron ab, was dazu führt, dass bei Betätigung des Buttons die App so lange einfriert, bis das Ergebnis von der longTask()
-Methode zurückgeliefert wird.
struct ContentView: View {
@State private var result = 0
var body: some View {
VStack {
Button("Start long task") {
result = longTask()
}
Text("Ergebnis: \(result)")
}
}
}
func longTask() -> Int {
var result = 0
for value in 1...10_000_000 {
result += value
}
return result
}
Die optimierte Variante mittels async
und await
zeigt das folgende Code-Beispiel. Die longTask()
-Methode ist nun als async
deklariert und kann ihre Befehle somit im Hintergrund ausführen (ohne die ganze App zu blockieren). Entsprechend muss beim Aufruf von longTask()
wie beschrieben das await
-Keyword gesetzt werden.
struct ContentView: View {
@State private var result = 0
var body: some View {
VStack {
Button("Start long task") {
async {
result = await longTask()
}
}
Text("Ergebnis: \(result)")
}
}
}
func longTask() async -> Int {
var result = 0
for value in 1...10_000_000 {
result += value
}
return result
}
Durch diese Änderungen friert die App nicht länger ein, wenn man den Button betätigt. Ein Detail ist hierbei jedoch noch besonders wichtig: await
kann nur in asynchronen Funktionen genutzt werden! Aus diesem Grund ist der Aufruf von longTask()
in der Action des Button auch in einen async
-Block gepackt. Da die body
-Property selbst nicht async
ist, kann man aus ihr heraus keine await
-Aufrufe durchführen. Doch durch Einsatz eines async
-Blocks könnt ihr an einer beliebigen Stelle im Code einen asynchronen Aufruf starten.
Euer Thomas
Schreibe einen Kommentar