OperationQueue es una cola de tareas de alto nivel en iOS y macOS construida sobre Grand Central Dispatch. Según Apple Developer Documentation, 2026, OperationQueue gestiona instancias de Operation — objetos que encapsulan una unidad de trabajo. A diferencia de DispatchQueue, OperationQueue soporta dependencias entre operaciones, prioridades, observación KVO y cancelación de tareas en ejecución. OperationQueue administra automáticamente un grupo de hilos, distribuyendo las operaciones entre los recursos disponibles del sistema.
Puntos Clave
OperationQueue es una clase del framework Foundation que gestiona la ejecución de objetos Operation. A diferencia de DispatchQueue, OperationQueue no requiere especificar explícitamente el modo serial o concurrente — la cantidad de operaciones que se ejecutan simultáneamente se controla mediante la propiedad maxConcurrentOperationCount. Un valor de 1 convierte la cola en secuencial, cualquier otro valor la hace concurrente.
Operation es una clase abstracta que representa una unidad de trabajo. Cada operación tiene un estado: ready, executing, finished o cancelled. Los estados son compatibles con KVO (Key-Value Observing), lo que permite reaccionar a cambios — por ejemplo, actualizar la interfaz cuando una operación finaliza. Operation gestiona automáticamente las banderas isExecuting e isFinished.
Según Apple (2026), OperationQueue utiliza GCD internamente pero añade funcionalidades no disponibles en DispatchQueue: dependencias, prioridades y cancelación de operaciones. Si la aplicación pasa a segundo plano, OperationQueue suspende la ejecución y la reanuda al regresar. OperationQueue también considera automáticamente la cantidad de núcleos de CPU y selecciona el número óptimo de hilos.
Cada operación pasa por cuatro estados: pending (pendiente), ready (lista), executing (en ejecución) y finished (finalizada). El estado cancelled puede ocurrir en cualquier etapa antes de la finalización. Las transiciones de estado se rastrean mediante KVO — esta es la base para actualizaciones reactivas de la interfaz. OperationQueue elimina automáticamente las operaciones completadas de la cola y notifica a las operaciones dependientes que su prerrequisito se ha cumplido, activando su ejecución.
Operation es una clase abstracta que requiere sobrescribir el método main() o start(). El código de la tarea se coloca en el método main(), y los estados isExecuting e isFinished se gestionan automáticamente. Para operaciones asíncronas, es necesario sobrescribir start() y gestionar manualmente las banderas de estado.
BlockOperation es una implementación concreta de Operation que ejecuta uno o más bloques de código. BlockOperation se vuelve concurrente si se añaden varios bloques mediante addExecutionBlock(). La operación finaliza solo después de que todos los bloques añadidos se hayan ejecutado. BlockOperation es una alternativa conveniente para tareas simples sin herencia.
| Característica | Operation | BlockOperation |
|---|---|---|
| Tipo de Clase | Abstracta | Concreta |
| Herencia | Requerida | No requerida |
| Asincronía | Gestión manual de KVO | Automática |
| Bloques de Código | Uno en main() | Uno o varios |
| Uso | Tareas complejas con estado | Tareas simples de una sola vez |
| Adecuado para | Dependencias, cancelación, progreso | Bloques rápidos, finalización |
| Memoria | Mayor debido a KVO y estado | Mínima, ligera |
Para crear una operación personalizada, herede de Operation y sobrescriba main(). Dentro, verifique la bandera isCancelled antes de operaciones costosas para garantizar una cancelación rápida. Esto es crítico para descargar archivos grandes o procesar lotes de datos. Elegir entre Operation y BlockOperation depende de la complejidad de la tarea: para acciones simples de una sola vez, BlockOperation es suficiente; para lógica reutilizable con estado, herede de Operation.
Las dependencias son la ventaja clave de OperationQueue sobre DispatchQueue. El método addDependency(_:) especifica que la operación B se ejecuta solo después de que la operación A finalice. Las dependencias forman un grafo acíclico dirigido (DAG): si se añade una dependencia cíclica, la cola la ignora y las operaciones no se inician.
La prioridad de una operación se establece mediante la propiedad queuePriority con valores: .veryLow, .low, .normal, .high, .veryHigh. La prioridad afecta el orden de inicio entre las operaciones listas, pero no anula las dependencias. OperationQueue primero resuelve las dependencias, luego aplica la prioridad entre las operaciones disponibles.
Un escenario típico es la carga de datos de perfil: primero cargar el usuario, luego basándose en su id cargar amigos y publicaciones. Establecer una dependencia entre cargar el usuario y cargar amigos garantiza el orden correcto sin manejadores de finalización anidados.
La propiedad maxConcurrentOperationCount limita la cantidad de operaciones que se ejecutan simultáneamente. Un valor de 1 crea una cola secuencial, el valor predeterminado (NSOperationQueueDefaultMaxConcurrentOperationCount) es óptimo para el sistema y depende de la carga actual del dispositivo. Una configuración adecuada de este parámetro previene el consumo excesivo de recursos: para cargar imágenes, 4–6 operaciones concurrentes son suficientes; para tareas intensivas de CPU, use la cantidad de núcleos del procesador.
Elegir entre OperationQueue y DispatchQueue depende de la complejidad de la tarea. DispatchQueue es una herramienta ligera para llamadas asíncronas simples. OperationQueue es una solución más pesada para escenarios complejos con muchas tareas interrelacionadas. Apple recomienda comenzar con DispatchQueue y cambiar a OperationQueue solo cuando se necesiten dependencias o cancelación. Para la mayoría de los proyectos iOS, una combinación de ambas herramientas proporciona un equilibrio óptimo entre rendimiento y flexibilidad.
Según Ray Wenderlich (2025), en proyectos iOS grandes, OperationQueue se utiliza para cargar contenido con progreso y cancelación, mientras que DispatchQueue se usa para todas las demás operaciones asíncronas. La proporción es aproximadamente 20 a 80 a favor de DispatchQueue.
Veamos tres ejemplos: un BlockOperation simple, una Operation personalizada con dependencias y una operación cancelable para carga de datos.
El caso más simple — ejecutar un bloque en OperationQueue y manejar el resultado mediante completionBlock. Cada Operation tiene una propiedad completionBlock incorporada, que se llama después de que main() finaliza.
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
La dependencia garantiza que parseOperation se inicie solo después de que downloadOperation finalice. Esto elimina la necesidad de callbacks anidados.
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
Sobrescriba main() con verificaciones periódicas de isCancelled. Esto permite que la operación se detenga inmediatamente al cancelarse, sin esperar a que finalice una operación costosa.
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) }
}
}
La cancelación de una operación establece la bandera isCancelled en true, pero no detiene un método main() que ya se está ejecutando. El código dentro de main() debe verificar isCancelled por sí mismo y terminar cuando sea necesario. Esta es una decisión arquitectónica de Apple — que permite al desarrollador liberar recursos correctamente al cancelar.
La observación KVO de las propiedades isFinished e isExecuting permite reaccionar a la finalización de operaciones sin callbacks explícitos. OperationQueue elimina automáticamente las operaciones completadas de la cola, pero permanecen en memoria mientras haya referencias fuertes a ellas. KVO es la base para integrar OperationQueue con frameworks reactivos como RxSwift o Combine.
Suscribirse a isCancelled mediante KVO permite actualizar la interfaz al cancelar una operación — por ejemplo, mostrar un marcador de posición en lugar de una descarga cancelada. La propiedad isCancelled es compatible con KVO, lo que la hace conveniente para pipelines reactivos.
No cree grandes cantidades de operaciones — cada Operation es un objeto separado en memoria. Si una tarea es corta y no requiere dependencias, use DispatchQueue directamente. OperationQueue está justificada para escenarios complejos con dependencias explícitas, cancelación y monitoreo de progreso.
Verifique isCancelled antes de operaciones costosas dentro del método main(). En casos de descarga de archivos o procesamiento de imágenes, verificar después de cada paso significativo garantiza una respuesta rápida a la cancelación. Use if isCancelled { return } al inicio de main() y después de cada operación importante.
Gestione completionBlock adecuadamente. La propiedad completionBlock de una operación se llama después de que main() finaliza, incluso si la operación fue cancelada. Verifique isCancelled dentro de completionBlock para evitar actualizar la interfaz con datos erróneos. OperationQueue.main es una cola segura para hilos para operaciones de interfaz, similar a DispatchQueue.main.
Evite dependencias cíclicas — hacen que ninguna de las operaciones en el ciclo se inicie. OperationQueue no detecta ciclos automáticamente: si A depende de B y B depende de A, ambas permanecerán en estado ready para siempre. Planifique el grafo de dependencias con anticipación.
Preguntas Frecuentes
OperationQueue está construida sobre GCD y añade dependencias, prioridades, KVO y cancelación de operaciones. DispatchQueue es una herramienta más ligera para tareas asíncronas simples sin estas capacidades.
Establezca la propiedad maxConcurrentOperationCount en 1. Esto convierte OperationQueue en una cola secuencial conservando todas las ventajas — dependencias, prioridades y cancelación.
El método cancel() establece la bandera isCancelled pero no detiene el método main() en ejecución. El código de la operación debe verificar isCancelled por sí mismo y terminar. La cancelación solo funciona para operaciones pendientes y listas.
Debe heredar de Operation cuando necesite gestión de estado, asincronía o reutilización de lógica. BlockOperation es adecuado para tareas simples de una sola vez sin herencia.
No, a menos que llame a waitUntilFinished con el parámetro true en el hilo principal. Las operaciones se ejecutan en hilos de fondo por defecto y los resultados se devuelven mediante OperationQueue.main.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también