Sobes.tech
Middle

¿Por qué no se recomienda cargar el hilo principal en iOS y qué métodos existen para evitarlo?

sobes.tech AI

Respuesta de la IA

La corriente principal se encarga de actualizar la interfaz de usuario y manejar los eventos de UI. Cualquier operación prolongada (solicitudes de red, cálculos intensivos, trabajo con archivos) en la corriente principal la bloqueará, lo que resultará en una interfaz "congelada", baja capacidad de respuesta de la aplicación e incluso su bloqueo (timeout del watchdog).

Formas de evitar la carga en la corriente principal:

  1. Grand Central Dispatch (GCD): Permite ejecutar tareas de forma asíncrona en colas en segundo plano.

    • DispatchQueue.global(): Obtiene colas globales en segundo plano con diferentes prioridades.
    • DispatchQueue.main: Cola principal para actualizar la UI.
    • async { ... }: Ejecuta un bloque de código de forma asíncrona.
    // ejecutar tarea pesada en segundo plano
    DispatchQueue.global(qos: .userInitiated).async {
        // cálculos pesados o solicitud de red
    
        // actualizar la UI en la corriente principal
        DispatchQueue.main.async {
            // actualizar la interfaz de usuario
        }
    }
    
  2. Colas de Operaciones (Operation & OperationQueue): Una abstracción de nivel superior sobre las colas GCD, que soporta dependencias entre operaciones, cancelación y suspensión.

    • OperationQueue(): Crear una cola de operaciones.
    • Operation: Clase abstracta para tareas que se pueden agregar a la cola.
    • addOperation(_:): Agregar una operación a la cola.
    let downloadOperation = BlockOperation {
        // descargar datos
    }
    
    let parseOperation = BlockOperation {
        // analizar datos
    }
    
    // dependencia: el análisis comienza después de la descarga
    parseOperation.addDependency(downloadOperation)
    
    let queue = OperationQueue()
    queue.addOperation(downloadOperation)
    queue.addOperation(parseOperation)
    
  3. Concurrencia (async/await): Enfoque moderno en Swift para programación asíncrona.

    • async: Marca una función como asíncrona.
    • await: Espera a que una operación asíncrona termine.
    • Task: Crear una nueva tarea concurrente.
    func fetchData() async throws -> Data {
        let url = URL(string: "https://example.com/data")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    }
    
    func updateUI() {
        Task {
            do {
                let data = try await fetchData()
                // procesar datos
                // actualizar la UI en la corriente principal automáticamente
                // (si la tarea se crea en un Actor principal o DispatchQueue.main)
            } catch {
                // manejar error
            }
        }
    }
    
  4. Actores: Previenen condiciones de carrera al acceder desde diferentes contextos concurrentes, asegurando acceso exclusivo a su estado.

    actor DataStore {
        private var data: [String] = []
    
        func addData(_ item: String) {
            data.append(item)
        }
    
        func getData() -> [String] {
            return data
        }
    }
    
    let store = DataStore()
    
    Task {
        await store.addData("item1")
    }
    

La elección entre GCD, Colas de Operaciones y Concurrencia depende de la complejidad de la tarea, el nivel de control necesario y los requisitos de estructuración del código. La concurrencia es el enfoque preferido en aplicaciones modernas por su legibilidad y seguridad.