Sobes.tech
Middle

Parlez-moi du mécanisme d'annulation dans les opérations.

sobes.tech IA

Réponse de l'IA

Le mécanisme d’annulation des opérations dans iOS repose sur l’utilisation du protocole Cancellable et des types associés.

Composants principaux:

  1. Protocole Cancellable: Définit l’exigence d’avoir une méthode cancel(), qui initie l’annulation.

    // Fragment de définition du protocole
    public protocol Cancellable {
        func cancel()
    }
    
  2. AnyCancellable: Type enveloppe qui stocke tout type conforme à Cancellable, et appelle automatiquement cancel() lors de la désinitialisation. Utile pour gérer le cycle de vie des abonnements/opérations.

    // Exemple d’utilisation
    var cancellable = AnyCancellable {
        // Action d’annulation
        print("Opération annulée")
    }
    
    // Dans le scope où cancellable est défini, à la sortie, il appellera cancel()
    
  3. Annulation dans Combine: Dans le framework Combine, la majorité des Publisher fournissent une souscription (Subscription), qui implémente le protocole Cancellable. En appelant cancel() sur Subscription, le flux de données s’arrête. Habituellement, Subscription est enveloppé dans AnyCancellable et stocké.

    // Exemple dans Combine
    import Combine
    
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var cancellable: AnyCancellable? = publisher.sink { completion in
        print("Complétion: \(completion)")
    } receiveValue: { date in
        print("Valeur: \(date)")
    }
    
    // Annulation après un certain temps
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        cancellable?.cancel() // Appel à cancel() sur AnyCancellable
        cancellable = nil // Nettoyage de la référence
    }
    
  4. Operation et OperationQueue: Dans les API anciennes, il existe aussi un mécanisme d’annulation. La classe Operation possède la méthode cancel() et la propriété isCancelled. OperationQueue vérifie cette propriété et ne planifie pas les opérations annulées.

    import Foundation
    
    class MyOperation: Operation {
        override func main() {
            if isCancelled { // Vérification de l’état d’annulation
                print("Opération annulée avant de commencer")
                return
            }
    
            // Exécution de la tâche
            for i in 0..<1000 {
                if isCancelled { // Vérification pendant l’exécution
                    print("Opération annulée pendant l’exécution")
                    return
                }
                // Travail lourd ou appel API
                print("Étape \(i)")
            }
    
            print("Opération terminée")
        }
    }
    
    let queue = OperationQueue()
    let operation = MyOperation()
    
    queue.addOperation(operation)
    
    // Annuler l’opération après un certain temps
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
       operation.cancel() // Appel à cancel()
    }
    
    // Attendre la fin (pas recommandé sur le thread principal dans une vraie application)
    // queue.waitUntilAllOperationsAreFinished()
    

Le mécanisme d’annulation dans iOS est asynchrone et coopératif. L’appel à cancel() signale l’intention d’annuler l’opération/flux de données, mais l’arrêt réel dépend de la façon dont l’opération gère ce signal (par exemple, en vérifiant isCancelled ou en réagissant à l’annulation de l’abonnement).

La gestion des objets annulables (notamment AnyCancellable) se fait souvent en les stockant dans des collections (Set<AnyCancellable>) ou des propriétés d’objets, pour garantir que cancel() soit appelé lors de la désinitialisation du conteneur ou lors de sa suppression explicite de la collection.