Einleitung: Warum „warten“ nicht so einfach ist, wie es scheint
\n\nStellen Sie sich vor: Sie schreiben eine iOS-App in Swift 3. Sie müssen eine Animation anzeigen und nach ein paar Sekunden wieder ausblenden. Oder eine Anfrage an den Server senden, aber nicht sofort, sondern mit einer Verzögerung. Was könnte einfacher sein? Man nimmt sleep(2) – und fertig. Aber wenn Sie das tun, wird Ihre App zu einem Eisblock: Die Oberfläche friert ein, der Benutzer tippt auf den Bildschirm, und das Ergebnis sind negative Bewertungen und ein Verlust an Reputation.
Die Frage „How to program a delay in Swift 3“ hat auf Stack Overflow tausende Aufrufe. Das ist kein Zufall: Anfänger tappen immer wieder in dieselben Fallen. In diesem Artikel geben wir nicht nur ein fertiges Rezept. Wir tauchen tief unter die Haube des Verzögerungsmechanismus, verstehen, wie DispatchQueue.main.asyncAfter funktioniert, und erkennen, warum sleep böse ist. Außerdem zeige ich Ihnen einen Lifehack, der Ihnen Stunden beim Debuggen spart.
Warum sleep() ein Anti-Pattern in Swift ist
\n\nLassen Sie uns gleich das häufigste Missverständnis klären. Viele, die aus anderen Sprachen kommen (z. B. aus Python mit time.sleep()), versuchen Folgendes:
sleep(2) // blockiert den Thread für 2 Sekunden\nprint("2 Sekunden sind vergangen")\n\nDieser Code blockiert den aktuellen Thread. Wenn Sie ihn im Hauptthread (main thread) aufrufen – die App „schläft“ für 2 Sekunden. Die Benutzeroberfläche wird nicht aktualisiert, Tasten können nicht gedrückt werden, Animationen laufen nicht. iOS wird Ihre App beenden, wenn der Hauptthread zu lange blockiert ist (normalerweise länger als 10 Sekunden).
\n\nAußerdem berücksichtigt sleep() den Zustand des RunLoop nicht. Es ist ein grober Systemaufruf, der dem System nicht erlaubt, Ereignisse normal zu verarbeiten. In Swift 3 (und später) ist der richtige Weg die Verwendung von Grand Central Dispatch (GCD).
DispatchQueue.main.asyncAfter: Der richtige Weg, eine Verzögerung zu erzeugen
\n\nDie gebräuchlichste und empfohlene Methode, um die Ausführung von Code in Swift 3 zu verzögern, ist die Methode asyncAfter von GCD. So sieht sie aus:
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n print("2 Sekunden sind vergangen (nicht-blockierender Modus)")\n}\n\nHier sagen wir dem System: „Führe diesen Codeblock in 2 Sekunden ab dem aktuellen Zeitpunkt im Hauptthread aus.“ Der Hauptthread bleibt dabei frei – Animationen laufen, Tasten werden gedrückt, der Benutzer ist zufrieden.
\n\nAber lassen Sie uns tiefer graben. Was ist deadline? Warum .now() + 2.0 und nicht einfach 2.0? Und was passiert „unter der Haube“?
Anatomie von asyncAfter: deadline, DispatchTime und DispatchQoS
\n\nasyncAfter akzeptiert einen Parameter deadline vom Typ DispatchTime. Dies ist nicht nur eine Anzahl von Millisekunden, sondern ein absoluter Zeitpunkt, der an die Systemuhr gebunden ist. Wenn Sie .now() + 2.0 schreiben, berechnet GCD: „aktuelle Zeit + 2 Sekunden“ und stellt die Aufgabe mit diesem Zeitstempel in die Warteschlange.
Unter der Haube verwendet GCD mach_absolute_time() – einen Hardware-Timer, der unabhängig von Änderungen der Systemzeit ist. Das heißt, wenn der Benutzer die Uhr zurückstellt, wird Ihre Verzögerung nicht kaputtgehen (im Gegensatz zu Timer, der sich unvorhersehbar verhalten kann).
Ein wichtiger Punkt: deadline ist die minimale Zeit bis zur Ausführung. GCD garantiert nicht, dass der Code genau nach 2 Sekunden ausgeführt wird. Wenn das System beschäftigt ist (z. B. bei einer komplexen Datenverarbeitung), kann sich die Ausführung verzögern. Für die meisten UI-Aufgaben ist das nicht kritisch, aber für hochpräzise Timer (z. B. in Spielen) verwenden Sie besser CADisplayLink.
Ein weiterer Parameter ist qos (Quality of Service). Sie können die Priorität der Aufgabe angeben:
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1.0) {\n // Aufgabe mit hoher Priorität\n}\n\n
Blogs
Buchempfehlungen
Lesen Sie auch
So ermitteln Sie den Typ einer Variable in Swift: Vollständige Anleitung mit Codebeispielen
Fehlerbehandlung in JavaScript: try/catch, async/await und fortgeschrittene Muster
Testen in C#: Unit, Integration, E2E — Vollständiger Leitfaden für .NET
Initialisierung von ArrayList in Java in einer Zeile: Geheimnisse und Fallstricke
Fehlerbehandlung in Kotlin: try/catch, Null Safety und Sealed Classes