Introduction : pourquoi « attendre » n'est pas aussi simple qu'il n'y paraît
\n\nImaginez : vous développez une application iOS en Swift 3. Vous devez afficher une animation, puis la masquer après quelques secondes. Ou envoyer une requête à un serveur, mais pas immédiatement, avec un délai. Cela semble simple, non ? Il suffit d'écrire sleep(2) et le tour est joué. Mais si vous faites cela, votre application se transformera en glaçon : l'interface se bloquera, l'utilisateur commencera à taper sur l'écran, et au final, vous obtiendrez un avis négatif et une perte de classement.
La question « How to program a delay in Swift 3 » a cumulé des milliers de vues sur Stack Overflow. Et ce n'est pas un hasard : les débutants tombent constamment dans les mêmes pièges. Dans cet article, nous ne nous contenterons pas de donner une recette toute faite. Nous allons sous le capot du mécanisme des délais, comprendre comment fonctionne DispatchQueue.main.asyncAfter, et saisir pourquoi sleep est un mal. Et je vais aussi vous montrer une astuce qui vous fera gagner des heures de débogage.
Pourquoi sleep() est un anti-patron en Swift
\n\nCommençons par dissiper l'idée reçue la plus courante. Beaucoup de ceux qui viennent d'autres langages (par exemple, de Python avec son time.sleep()) essaient de faire ceci :
sleep(2) // bloque le thread pendant 2 secondes\nprint("2 secondes se sont écoulées")\n\nCe code bloque le thread actuel. Si vous l'appelez sur le thread principal (main thread) — c'est fini, l'application « s'endort » pendant 2 secondes. L'interface utilisateur ne se met pas à jour, les boutons ne répondent pas, les animations ne fonctionnent pas. iOS tuera votre application si le thread principal est bloqué trop longtemps (généralement plus de 10 secondes).
\n\nDe plus, sleep() ne tient pas compte de l'état du RunLoop. C'est un appel système brutal qui empêche le système de traiter normalement les événements. En Swift 3 (et versions ultérieures), la bonne approche est d'utiliser Grand Central Dispatch (GCD).
DispatchQueue.main.asyncAfter : la bonne façon de créer un délai
\n\nLa méthode la plus courante et recommandée pour différer l'exécution de code en Swift 3 est la méthode asyncAfter de GCD. Voici à quoi elle ressemble :
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n print("2 secondes se sont écoulées (mode non bloquant)")\n}\n\nIci, nous disons au système : « Dans 2 secondes à partir du moment présent, exécute ce bloc de code sur le thread principal ». Le thread principal reste libre — les animations fonctionnent, les boutons répondent, l'utilisateur est content.
\n\nMais creusons plus profondément. Qu'est-ce que deadline ? Pourquoi .now() + 2.0 et pas simplement 2.0 ? Et que se passe-t-il « sous le capot » ?
Anatomie de asyncAfter : deadline, DispatchTime et DispatchQoS
\n\nasyncAfter prend un paramètre deadline de type DispatchTime. Ce n'est pas simplement un nombre de millisecondes, mais un point absolu dans le temps, lié à l'horloge système. Lorsque vous écrivez .now() + 2.0, GCD calcule : « heure actuelle + 2 secondes » et place la tâche dans la file d'attente avec cette étiquette.
Sous le capot, GCD utilise mach_absolute_time() — un minuteur matériel qui ne dépend pas des changements de l'heure système. Autrement dit, si l'utilisateur recule l'horloge, votre délai ne sera pas perturbé (contrairement à Timer, qui peut se comporter de manière imprévisible).
Un détail important : deadline est le temps minimal avant l'exécution. GCD ne garantit pas que le code s'exécutera exactement dans 2 secondes. Si le système est occupé (par exemple, en plein traitement de données complexes), l'exécution peut être retardée. Pour la plupart des tâches d'interface utilisateur, ce n'est pas critique, mais pour les minuteurs de haute précision (par exemple, dans les jeux), il est préférable d'utiliser CADisplayLink.
Un autre paramètre est qos (Quality of Service). Vous pouvez spécifier la priorité de la tâche :
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1.0) {\n // tâche à haute priorité\n}\n\n
Blogs
Book Recommendations
Lire aussi
Vérifier si une clé existe dans une map en Go : guide complet
Automatisation des tâches en TypeScript : comment arrêter de faire un travail ennuyeux à la main
Salaires des développeurs Rust en Russie : aperçu du marché avancé
UIAlertView en Swift : 5 erreurs fatales et comment les éviter
Mise en cache en Swift : Redis, Memcached et solutions intégrées — niveau avancé