Concurrencia y multiproceso en Swift: técnicas avanzadas

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y multiproceso en Swift: nivel avanzado

La concurrencia (concurrency) es uno de los temas más complejos e importantes en el desarrollo para iOS/macOS. A nivel avanzado, Swift ofrece herramientas potentes: desde el clásico Grand Central Dispatch (GCD) hasta el modelo moderno async/await y el estricto sistema de Actores. En este artículo, analizaremos cómo gestionar hilos de manera eficiente, evitar condiciones de carrera y escribir código seguro para hilos.



1. Grand Central Dispatch (GCD): trabajo con colas y grupos

GCD sigue siendo la base del multiproceso en Swift. Sin embargo, a nivel avanzado es importante entender no solo la diferencia entre main y global(), sino también saber gestionar dependencias de tareas.

Creación de colas propias

let serialQueue = DispatchQueue(label: "com.pythonlib.serial")let concurrentQueue = DispatchQueue(label: "com.pythonlib.concurrent", attributes: .concurrent)

serialQueue.async { print("Tarea 1 en cola secuencial")}concurrentQueue.async { print("Tarea 2 en cola concurrente")}

DispatchGroup: sincronización de múltiples tareas

let group = DispatchGroup()let queue = DispatchQueue.global()

queue.async(group: group) { sleep(1) print("Carga de datos 1")}queue.async(group: group) { sleep(2) print("Carga de datos 2")}

group.notify(queue: DispatchQueue.main) { print("Todas las cargas completadas, actualizando UI")}

Usa DispatchGroup cuando necesites esperar la finalización de varias operaciones paralelas (por ejemplo, carga de imágenes o análisis JSON).



2. Modelo moderno async/await y Task

A partir de Swift 5.5, el lenguaje incorporó soporte nativo para asincronía mediante las palabras clave async y await. Esto simplifica la lectura del código y elimina la "pirámide de closures".

Declaración y llamada de una función asíncrona

func fetchUserData() async -> String {    // Simulación de solicitud de red    try? await Task.sleep(nanoseconds: 2_000_000_000)    return "Datos de usuario cargados"}

Task { let result = await fetchUserData() print(result) // Muestra "Datos de usuario cargados"}

Llamadas paralelas con async let

func loadImage() async -> Data { return Data() }func loadMetadata() async -> String { return "meta" }

Task { async let image = loadImage() async let metadata = loadMetadata() let result = try await (image, metadata) print("Imagen: \\(result.0), metadatos: \\(result.1)")}

async let permite ejecutar varias tareas asíncronas en paralelo y esperar a que todas terminen. Esto es más eficiente que una llamada secuencial.



3. Actores: seguridad en hilos a nivel de lenguaje

Los Actores (Actors) son un nuevo mecanismo para proteger contra condiciones de carrera. Garantizan que el acceso a su estado se sincronice automáticamente.

Definición y uso de un actor

actor BankAccount {    private var balance: Double = 0.0        func deposit(amount: Double) {        balance += amount        print("Saldo después del depósito: \\(balance)")    }        func withdraw(amount: Double) -> Bool {        guard balance >= amount else { return false }        balance -= amount        return true    }        func getBalance() -> Double { balance }}

Task { let account = BankAccount() await account.deposit(amount: 100) let success = await account.withdraw(amount: 50) print("Retiro exitoso: \\(success)")}

Todos los métodos del actor están aislados por defecto; solo se pueden llamar mediante await. Esto evita la modificación accidental de datos desde múltiples hilos.

Métodos no aislados (nonisolated)

actor Logger {    nonisolated func log(message: String) {        print("Log: \\(message)")\                

Blogs

Book Recommendations