Sobes.tech
Middle

Fale-me sobre o mecanismo de cancelamento nas operações.

sobes.tech IA

Resposta da IA

O mecanismo de cancelamento de operações no iOS baseia-se no uso do protocolo Cancellable e tipos relacionados.

Componentes principais:

  1. Protocolo Cancellable: Define o requisito de ter um método cancel(), que inicia o cancelamento.

    // Fragmento de definição do protocolo
    public protocol Cancellable {
        func cancel()
    }
    
  2. AnyCancellable: Tipo envoltório que armazena qualquer tipo que cumpra Cancellable, e chama automaticamente cancel() ao desassinar. É útil para gerir o ciclo de vida de assinaturas/operações.

    // Exemplo de uso
    var cancellable = AnyCancellable {
        // Ação de cancelamento
        print("Operação cancelada")
    }
    
    // Dentro do escopo onde `cancellable` é definido, ao sair, ele chamará `cancel()`
    
  3. Cancelamento no Combine: No framework Combine, a maioria dos Publisher fornece uma assinatura (Subscription), que implementa o protocolo Cancellable. Ao chamar cancel() em Subscription, o fluxo de dados para. Normalmente, Subscription é envolvido em AnyCancellable e mantido.

    // Exemplo no Combine
    import Combine
    
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var cancellable: AnyCancellable? = publisher.sink { completion in
        print("Conclusão: \(completion)")
    } receiveValue: { date in
        print("Valor: \(date)")
    }
    
    // Cancelar após algum tempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        cancellable?.cancel() // Chamada a `cancel()` em `AnyCancellable`
        cancellable = nil // Limpeza da referência
    }
    
  4. Operation e OperationQueue: Em APIs antigas, também há um mecanismo de cancelamento. A classe Operation possui o método cancel() e a propriedade isCancelled. OperationQueue verifica essa propriedade e não agenda operações canceladas.

    import Foundation
    
    class MyOperation: Operation {
        override func main() {
            if isCancelled { // Verificação do estado de cancelamento
                print("Operação cancelada antes de iniciar")
                return
            }
    
            // Execução da tarefa
            for i in 0..<1000 {
                if isCancelled { // Verificação durante a tarefa
                    print("Operação cancelada durante a execução")
                    return
                }
                // Trabalho pesado ou chamada de API
                print("Passo \(i)")
            }
    
            print("Operação finalizada")
        }
    }
    
    let queue = OperationQueue()
    let operation = MyOperation()
    
    queue.addOperation(operation)
    
    // Cancelar operação após algum tempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
       operation.cancel() // Chamada a `cancel()`
    }
    
    // Esperar pela finalização (não recomendado na thread principal)
    // queue.waitUntilAllOperationsAreFinished()
    

O mecanismo de cancelamento no iOS é assíncrono e cooperativo. A chamada cancel() sinaliza a intenção de cancelar a operação/fluxo de dados, mas a parada real depende de como a própria operação trata esse sinal (por exemplo, verificando isCancelled ou reagindo à cancelamento da assinatura).

A gestão de objetos canceláveis (especialmente AnyCancellable) geralmente é feita armazenando-os em coleções (Set<AnyCancellable>) ou propriedades de objetos, para garantir que cancel() seja chamado na desinicialização do contêiner ou na sua remoção explícita da coleção.