Introducción a la concurrencia y el multihilo en Swift
Las aplicaciones modernas de iOS y macOS requieren cada vez más la ejecución de múltiples tareas simultáneamente. Ya sea la descarga de datos desde la red, el procesamiento de imágenes o cálculos matemáticos complejos, no se puede prescindir de una gestión adecuada de los hilos. En Swift, la concurrencia y el multihilo están implementados al más alto nivel, proporcionando al desarrollador herramientas potentes y seguras.
En este artículo analizaremos tres enfoques principales: Grand Central Dispatch (GCD), OperationQueue y la moderna palabra clave async/await, introducida en Swift 5.5. Aprenderás cómo elegir correctamente entre ellos y evitar errores típicos como las condiciones de carrera (race condition) y los interbloqueos (deadlock).
Grand Central Dispatch (GCD) — el clásico del multihilo en Swift
Grand Central Dispatch (GCD) es una biblioteca de bajo nivel de Apple que gestiona un pool de hilos. El desarrollador no necesita crear y destruir hilos manualmente — GCD lo hace automáticamente, distribuyendo las tareas entre los núcleos disponibles del procesador.
Colas principales de GCD
En GCD existen dos tipos de colas: seriales (serial) y concurrentes (concurrent). Las tareas en una cola serial se ejecutan una tras otra, mientras que en una cola concurrente pueden iniciarse simultáneamente.
// Creación de una cola seriallet serialQueue = DispatchQueue(label: "com.example.serial")serialQueue.async { print("Tarea 1")}serialQueue.async { print("Tarea 2")}
// Creación de una cola concurrentelet concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)concurrentQueue.async { print("Tarea concurrente A")}concurrentQueue.async { print("Tarea concurrente B")}Colas globales y QoS
GCD proporciona colas globales predefinidas con diferentes prioridades (Quality of Service). Úsalas cuando no sea necesario crear tu propia cola:
.userInteractive— para actualizaciones de la UI (máxima prioridad).userInitiated— para tareas iniciadas por el usuario.utility— para operaciones de fondo prolongadas.background— para tareas no críticas en tiempo
DispatchQueue.global(qos: .userInitiated).async { // Trabajo pesado let result = performComplexCalculation() DispatchQueue.main.async { // Volvemos al hilo principal para actualizar la UI self.updateUI(with: result) }}Importante: Siempre actualiza la UI solo en el hilo principal (DispatchQueue.main). Ignorar esta regla provoca fallos impredecibles en la aplicación.
OperationQueue — gestión de dependencias de tareas
Si GCD es una «navaja suiza», OperationQueue es un planificador completo con capacidad de cancelación, priorización y creación de dependencias entre operaciones. Cada operación es una instancia de la clase Operation (o su subclase BlockOperation).
Creación y ejecución de operaciones
let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 2 // Limitamos el número de operaciones concurrentes
let operation1 = BlockOperation { print("Operación 1")}let operation2 = BlockOperation { print("Operación 2")}
// Añadimos dependencia: operation2 comenzará solo después de que termine operation1operation2.addDependency(operation1)
operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)Cancelación y prioridades
A diferencia de GCD, OperationQueue permite cancelar una operación específica o toda la cola:
// Cancelar una operaciónoperation1.cancel()
// Cancelar toda la colaoperationQueue.cancelAllOperations()
// Establecer prioridadoperation1.