Sobes.tech
Middle

Cuéntame sobre el mecanismo de cancelación en las operaciones.

sobes.tech AI

Respuesta de la IA

El mecanismo de cancelación de operaciones en iOS se basa en el uso del protocolo Cancellable y tipos relacionados.

Componentes principales:

  1. Protocolo Cancellable: Define el requisito de tener un método cancel(), que inicia la cancelación.

    // Fragmento de definición del protocolo
    public protocol Cancellable {
        func cancel()
    }
    
  2. AnyCancellable: Tipo envoltorio que almacena cualquier tipo que cumpla con Cancellable, y llama automáticamente a cancel() al desasignarse. Es útil para gestionar el ciclo de vida de suscripciones/operaciones.

    // Ejemplo de uso
    var cancellable = AnyCancellable {
        // Acción de cancelación
        print("Operación cancelada")
    }
    
    // Dentro del ámbito donde se define cancellable, al salir se llamará a cancel()
    
  3. Cancelación en Combine: En el framework Combine, la mayoría de los Publisher proporcionan una suscripción (Subscription), que implementa el protocolo Cancellable. Al llamar a cancel() en Subscription, se detiene el flujo de datos. Normalmente, Subscription se envuelve en AnyCancellable y se mantiene.

    // Ejemplo en Combine
    import Combine
    
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var cancellable: AnyCancellable? = publisher.sink { completion in
        print("Finalización: \(completion)")
    } receiveValue: { date in
        print("Valor: \(date)")
    }
    
    // Cancelar después de un tiempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        cancellable?.cancel() // Llamada a cancel() en AnyCancellable
        cancellable = nil // Limpieza de la referencia
    }
    
  4. Operation y OperationQueue: En APIs antiguas, también existe un mecanismo de cancelación. La clase Operation tiene el método cancel() y la propiedad isCancelled. OperationQueue verifica esta propiedad y no programa operaciones canceladas.

    import Foundation
    
    class MyOperation: Operation {
        override func main() {
            if isCancelled { // Verificación del estado de cancelación
                print("Operación cancelada antes de comenzar")
                return
            }
    
            // Ejecución de la tarea
            for i in 0..<1000 {
                if isCancelled { // Verificación durante la ejecución
                    print("Operación cancelada durante la ejecución")
                    return
                }
                // Trabajo pesado o llamada a API
                print("Paso \(i)")
            }
    
            print("Operación finalizada")
        }
    }
    
    let queue = OperationQueue()
    let operation = MyOperation()
    
    queue.addOperation(operation)
    
    // Cancelar operación después de un tiempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
       operation.cancel() // Llamada a cancel()
    }
    
    // Esperar a que termine (en una aplicación real, no se recomienda en el hilo principal)
    // queue.waitUntilAllOperationsAreFinished()
    

El mecanismo de cancelación en iOS es asincrónico y cooperativo. La llamada a cancel() indica la intención de cancelar la operación/flujo de datos, pero la detención real depende de cómo la propia operación maneja esta señal (por ejemplo, verificando isCancelled o reaccionando a la cancelación de la suscripción).

La gestión de objetos cancelables (especialmente AnyCancellable) a menudo se realiza almacenándolos en colecciones (Set<AnyCancellable>) o propiedades de objetos, para garantizar que se llame a cancel() al desasignar el contenedor o al eliminarlo explícitamente de la colección.