Sobes.tech
Middle

Parla del meccanismo di annullamento nelle operazioni.

sobes.tech AI

Risposta dell'AI

Il meccanismo di cancellazione delle operazioni in iOS si basa sull’uso del protocollo Cancellable e sui tipi correlati.

Componenti principali:

  1. Protocollo Cancellable: Definisce il requisito di avere un metodo cancel(), che avvia la cancellazione.

    // Frammento di definizione del protocollo
    public protocol Cancellable {
        func cancel()
    }
    
  2. AnyCancellable: Tipo wrapper che memorizza qualsiasi tipo conforme a Cancellable, e chiama automaticamente cancel() al deallocamento. È utile per gestire il ciclo di vita di sottoscrizioni/operazioni.

    // Esempio di utilizzo
    var cancellable = AnyCancellable {
        // Azione di cancellazione
        print("Operazione annullata")
    }
    
    // Dentro lo scope in cui è definito cancellable, al suo uscire verrà chiamato cancel()
    
  3. Cancellazione in Combine: Nel framework Combine, la maggior parte dei Publisher fornisce una sottoscrizione (Subscription), che implementa il protocollo Cancellable. Chiamando cancel() su Subscription, il flusso di dati si interrompe. Di solito, Subscription viene avvolto in AnyCancellable e conservato.

    // Esempio in Combine
    import Combine
    
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var cancellable: AnyCancellable? = publisher.sink { completion in
        print("Completamento: \(completion)")
    } receiveValue: { date in
        print("Valore: \(date)")
    }
    
    // Cancellare dopo un po’ di tempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        cancellable?.cancel() // Chiamata a `cancel()` su `AnyCancellable`
        cancellable = nil // Pulizia del riferimento
    }
    
  4. Operation e OperationQueue: Nelle API più vecchie esiste anche un meccanismo di cancellazione. La classe Operation ha il metodo cancel() e la proprietà isCancelled. OperationQueue verifica questa proprietà e non pianifica le operazioni cancellate.

    import Foundation
    
    class MyOperation: Operation {
        override func main() {
            if isCancelled { // Verifica dello stato di cancellazione
                print("Operazione cancellata prima di iniziare")
                return
            }
    
            // Esecuzione del compito
            for i in 0..<1000 {
                if isCancelled { // Verifica durante il compito
                    print("Operazione cancellata durante l’esecuzione")
                    return
                }
                // Lavoro pesante o chiamata API
                print("Passo \(i)")
            }
    
            print("Operazione terminata")
        }
    }
    
    let queue = OperationQueue()
    let operation = MyOperation()
    
    queue.addOperation(operation)
    
    // Cancellare l’operazione dopo un po’ di tempo
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
       operation.cancel() // Chiamata a `cancel()`
    }
    
    // Attendere il completamento (non raccomandato sul main thread)
    // queue.waitUntilAllOperationsAreFinished()
    

Il meccanismo di cancellazione in iOS è asincrono e cooperativo. La chiamata cancel() segnala l’intenzione di annullare l’operazione/il flusso di dati, ma l’effettivo arresto dipende da come l’operazione stessa gestisce questo segnale (ad esempio, verificando isCancelled o reagendo alla cancellazione dell’abbonamento).

La gestione degli oggetti cancellabili (specialmente AnyCancellable) avviene spesso memorizzandoli in collezioni (Set<AnyCancellable>) o proprietà di oggetti, per garantire che cancel() venga chiamato al momento della deallocazione del contenitore o alla sua rimozione esplicita dalla collezione.