OperationQueue est une file d'attente de tâches de haut niveau dans iOS et macOS construite au-dessus de Grand Central Dispatch. Selon Apple Developer Documentation, 2026, OperationQueue gère des instances d'Operation — des objets qui encapsulent une unité de travail. Contrairement à DispatchQueue, OperationQueue prend en charge les dépendances entre les opérations, les priorités, l'observation KVO et l'annulation des tâches en cours d'exécution. OperationQueue gère automatiquement un pool de threads, répartissant les opérations sur les ressources système disponibles.
Points Clés
OperationQueue est une classe du framework Foundation qui gère l'exécution des objets Operation. Contrairement à DispatchQueue, OperationQueue ne nécessite pas de spécifier explicitement le mode série ou concurrent — le nombre d'opérations exécutées simultanément est contrôlé par la propriété maxConcurrentOperationCount. La valeur 1 rend la file d'attente séquentielle, toute autre valeur la rend concurrente.
Operation est une classe abstraite représentant une unité de travail. Chaque opération a un état : ready, executing, finished ou cancelled. Les états sont compatibles avec KVO (Key-Value Observing), ce qui permet de réagir aux changements — par exemple, mettre à jour l'interface lorsqu'une opération se termine. Operation gère automatiquement les indicateurs isExecuting et isFinished.
Selon Apple (2026), OperationQueue utilise GCD en interne mais ajoute des fonctionnalités non disponibles dans DispatchQueue : dépendances, priorités et annulation des opérations. Si l'application passe en arrière-plan, OperationQueue suspend l'exécution et la reprend au retour. OperationQueue prend également en compte automatiquement le nombre de cœurs CPU et sélectionne le nombre optimal de threads.
Chaque opération passe par quatre états : pending (en attente), ready (prête), executing (en cours d'exécution) et finished (terminée). L'état cancelled peut survenir à n'importe quelle étape avant la fin. Les transitions d'état sont suivies via KVO — c'est la base des mises à jour réactives de l'interface. OperationQueue supprime automatiquement les opérations terminées de la file et notifie les opérations dépendantes que leur prérequis est rempli, déclenchant leur exécution.
Operation est une classe abstraite qui nécessite de redéfinir la méthode main() ou start(). Le code de la tâche est placé dans la méthode main(), et les états isExecuting et isFinished sont gérés automatiquement. Pour les opérations asynchrones, il est nécessaire de redéfinir start() et de gérer manuellement les indicateurs d'état.
BlockOperation est une implémentation concrète d'Operation qui exécute un ou plusieurs blocs de code. BlockOperation devient concurrent si vous ajoutez plusieurs blocs via addExecutionBlock(). L'opération se termine uniquement après l'exécution de tous les blocs ajoutés. BlockOperation est une alternative pratique pour les tâches simples sans héritage.
| Caractéristique | Operation | BlockOperation |
|---|---|---|
| Type de Classe | Abstraite | Concrète |
| Héritage | Requis | Non requis |
| Asynchronie | Gestion manuelle KVO | Automatique |
| Blocs de Code | Un dans main() | Un ou plusieurs |
| Utilisation | Tâches complexes avec état | Tâches simples uniques |
| Adapté pour | Dépendances, annulation, progression | Blocs rapides, achèvement |
| Mémoire | Plus élevée à cause de KVO et de l'état | Minimale, légère |
Pour créer une opération personnalisée, héritez de Operation et redéfinissez main(). À l'intérieur, vérifiez l'indicateur isCancelled avant les opérations coûteuses pour garantir une annulation rapide. Ceci est critique pour le téléchargement de fichiers volumineux ou le traitement par lots de données. Le choix entre Operation et BlockOperation dépend de la complexité de la tâche : pour les actions simples uniques, BlockOperation suffit ; pour une logique réutilisable avec état, héritez de Operation.
Les dépendances sont l'avantage clé d'OperationQueue par rapport à DispatchQueue. La méthode addDependency(_:) spécifie que l'opération B s'exécute uniquement après la fin de l'opération A. Les dépendances forment un graphe orienté acyclique (DAG) : si une dépendance cyclique est ajoutée, la file d'attente l'ignore et les opérations ne démarrent pas.
La priorité d'une opération est définie via la propriété queuePriority avec les valeurs : .veryLow, .low, .normal, .high, .veryHigh. La priorité affecte l'ordre de démarrage parmi les opérations prêtes mais n'annule pas les dépendances. OperationQueue résout d'abord les dépendances, puis applique la priorité parmi les opérations disponibles.
Un scénario typique — le chargement des données de profil : d'abord charger l'utilisateur, puis en fonction de son id charger les amis et les publications. Définir une dépendance entre charger l'utilisateur et charger les amis garantit l'ordre correct sans gestionnaires d'achèvement imbriqués.
La propriété maxConcurrentOperationCount limite le nombre d'opérations exécutées simultanément. La valeur 1 crée une file d'attente séquentielle, la valeur par défaut (NSOperationQueueDefaultMaxConcurrentOperationCount) est optimale pour le système et dépend de la charge actuelle de l'appareil. La configuration appropriée de ce paramètre empêche une consommation excessive de ressources : pour le chargement d'images, 4 à 6 opérations concurrentes suffisent ; pour les tâches intensives en CPU, utilisez le nombre de cœurs du processeur.
Le choix entre OperationQueue et DispatchQueue dépend de la complexité de la tâche. DispatchQueue est un outil léger pour les appels asynchrones simples. OperationQueue est une solution plus lourde pour les scénarios complexes avec de nombreuses tâches interdépendantes. Apple recommande de commencer avec DispatchQueue et de passer à OperationQueue uniquement lorsque des dépendances ou une annulation sont nécessaires. Pour la plupart des projets iOS, une combinaison des deux outils offre un équilibre optimal entre performances et flexibilité.
Selon Ray Wenderlich (2025), dans les grands projets iOS, OperationQueue est utilisé pour charger du contenu avec progression et annulation, tandis que DispatchQueue est utilisé pour toutes les autres opérations asynchrones. Le ratio est d'environ 20 pour 80 en faveur de DispatchQueue.
Examinons trois exemples : un BlockOperation simple, une Operation personnalisée avec dépendances et une opération annulable pour le chargement de données.
Le cas le plus simple — exécuter un bloc sur OperationQueue et traiter le résultat via completionBlock. Chaque Operation a une propriété completionBlock intégrée, appelée après la fin de main().
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
La dépendance garantit que parseOperation ne démarre qu'après la fin de downloadOperation. Cela élimine le besoin de callbacks imbriqués.
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
Redéfinissez main() avec des vérifications périodiques de isCancelled. Cela permet à l'opération de s'arrêter immédiatement lors de l'annulation, sans attendre la fin d'une opération coûteuse.
class ImageLoadOperation: Operation {
override func main() {
guard !self.isCancelled else { return }
let image = self.downloadImage()
guard !self.isCancelled else { return }
OperationQueue.main.addOperation { self.display(image) }
}
}
L'annulation d'une opération définit l'indicateur isCancelled sur true, mais n'arrête pas la méthode main() déjà en cours d'exécution. Le code à l'intérieur de main() doit vérifier isCancelled par lui-même et se terminer si nécessaire. C'est une décision architecturale d'Apple — permettant au développeur de libérer correctement les ressources lors de l'annulation.
L'observation KVO des propriétés isFinished et isExecuting permet de réagir à l'achèvement des opérations sans callbacks explicites. OperationQueue supprime automatiquement les opérations terminées de la file, mais elles restent en mémoire tant qu'il y a des références fortes vers elles. KVO est la base pour intégrer OperationQueue avec des frameworks réactifs comme RxSwift ou Combine.
S'abonner à isCancelled via KVO permet de mettre à jour l'interface lors de l'annulation d'une opération — par exemple, afficher un espace réservé au lieu d'un téléchargement annulé. La propriété isCancelled est compatible KVO, ce qui la rend pratique pour les pipelines réactifs.
Ne créez pas de grandes quantités d'opérations — chaque Operation est un objet séparé en mémoire. Si une tâche est courte et ne nécessite pas de dépendances, utilisez DispatchQueue directement. OperationQueue est justifiée pour les scénarios complexes avec des dépendances explicites, une annulation et un suivi de progression.
Vérifiez isCancelled avant les opérations coûteuses à l'intérieur de la méthode main(). Dans les cas de téléchargement de fichiers ou de traitement d'images, vérifier après chaque étape importante garantit une réponse rapide à l'annulation. Utilisez if isCancelled { return } au début de main() et après chaque opération majeure.
Gérez completionBlock correctement. La propriété completionBlock d'une opération est appelée après la fin de main(), même si l'opération a été annulée. Vérifiez isCancelled à l'intérieur de completionBlock pour éviter de mettre à jour l'interface avec des données erronées. OperationQueue.main est une file d'attente thread-safe pour les opérations d'interface, similaire à DispatchQueue.main.
Évitez les dépendances cycliques — elles empêchent toute opération dans le cycle de démarrer. OperationQueue ne détecte pas automatiquement les cycles : si A dépend de B et B dépend de A, les deux resteront dans l'état ready pour toujours. Planifiez le graphe de dépendances à l'avance.
Foire Aux Questions
OperationQueue est construit sur GCD et ajoute des dépendances, des priorités, KVO et l'annulation d'opérations. DispatchQueue est un outil plus léger pour les tâches asynchrones simples sans ces capacités.
Définissez la propriété maxConcurrentOperationCount sur 1. Cela transforme OperationQueue en une file d'attente séquentielle tout en conservant tous les avantages — dépendances, priorités et annulation.
La méthode cancel() définit l'indicateur isCancelled mais n'arrête pas la méthode main() en cours d'exécution. Le code de l'opération doit vérifier isCancelled par lui-même et se terminer. L'annulation fonctionne uniquement pour les opérations en attente et prêtes.
Vous devez hériter de Operation lorsque vous avez besoin de gestion d'état, d'asynchronie ou de réutilisation de logique. BlockOperation convient aux tâches simples uniques sans héritage.
Non, sauf si vous appelez waitUntilFinished avec le paramètre true sur le thread principal. Les opérations s'exécutent sur des threads d'arrière-plan par défaut, et les résultats sont renvoyés via OperationQueue.main.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi