Introduction aux files d'attente de tâches en Swift
Les applications mobiles et de bureau modernes doivent être rapides et réactives. Si vous effectuez des calculs lourds ou chargez des données depuis le réseau directement dans le thread principal, votre application se bloquera et l'utilisateur la fermera simplement. La solution : les files d'attente de tâches (queues).
En Swift (iOS/macOS), la gestion de l'asynchrone repose sur trois technologies principales : Grand Central Dispatch (GCD), Operation Queue et la syntaxe moderne async/await. Dans cet article, nous allons décortiquer chacune d'elles depuis le début, montrer des exemples de code et expliquer quand les utiliser.
1. Grand Central Dispatch (GCD) et DispatchQueue
GCD est une bibliothèque bas niveau d'Apple pour gérer l'exécution parallèle de code. L'élément principal est DispatchQueue. La file d'attente exécute les tâches (closures) dans l'ordre où elles sont ajoutées.
Types de files d'attente
- Main Queue — file d'attente séquentielle du thread principal. Utilisée pour mettre à jour l'interface utilisateur.
- Global Queues — files d'attente parallèles avec différentes priorités (QoS :
.userInteractive,.userInitiated,.utility,.background). - Custom Queues — vos propres files d'attente (séquentielles ou parallèles).
Exemple : exécution d'une tâche en arrière-plan
import Foundation
// De manière asynchrone dans une file d'attente d'arrière-planDispatchQueue.global(qos: .background).async { // Travail lourd (chargement, traitement de données) let result = performHeavyTask() // Retour du résultat dans le thread principal DispatchQueue.main.async { updateUI(with: result) }}
func performHeavyTask() -> String { Thread.sleep(forTimeInterval: 2) // simulation de travail return "Terminé !"}
func updateUI(with text: String) { print("UI mis à jour : \\(text)")}Notez que .async ne bloque pas le thread appelant. Si vous devez attendre le résultat, utilisez .sync (mais n'appelez jamais .sync depuis le thread principal — vous obtiendrez un deadlock).
Exemple : file d'attente séquentielle
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async { print("Tâche 1")}serialQueue.async { print("Tâche 2")}// Sortie : Tâche 1, puis Tâche 22. Operation Queue — une approche plus flexible
OperationQueue est une surcouche de GCD, offrant une interface orientée objet. Vous créez une Operation (ou BlockOperation), configurez des dépendances et l'ajoutez à la file d'attente.
Avantages par rapport à GCD
- Annulation des tâches (
cancel()) - Dépendances entre les tâches
- Surveillance de l'état (isReady, isExecuting, isFinished)
- Nombre maximum d'opérations parallèles
Exemple : utilisation de base
let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 2 // pas plus de 2 tâches simultanément
let operation1 = BlockOperation { print("Chargement des données...") Thread.sleep(forTimeInterval: 1)}
let operation2 = BlockOperation { print("Traitement des données...") Thread.sleep(forTimeInterval: 1)}
// operation2 ne commencera qu'après la fin de operation1operation2.addDependency(operation1)
operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)Exemple : annulation d'une opération
let cancelableOp = BlockOperation { if !cancelableOp.isCancelled { print("J'effectue un travail important") }}
operationQueue.addOperation(cancelableOp)
// Après un certain temps, on annuleDispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { cancelableOp.cancel() print("Opération annulée")}\