Sobes.tech
Middle

Opowiedz o mechanizmie anulowania w operacjach.

sobes.tech AI

Odpowiedź od AI

Mechanizm anulowania operacji w iOS opiera się na użyciu protokołu Cancellable i powiązanych typów.

Główne komponenty:

  1. Protokół Cancellable: Określa wymóg posiadania metody cancel(), która inicjuje anulowanie.

    // Fragment definicji protokołu
    public protocol Cancellable {
        func cancel()
    }
    
  2. AnyCancellable: Typ opakowujący, który przechowuje dowolny typ zgodny z Cancellable, i automatycznie wywołuje cancel() podczas deinitializacji. Przydatny do zarządzania cyklem życia subskrypcji/operacji.

    // Przykład użycia
    var cancellable = AnyCancellable {
        // Akcja anulowania
        print("Operacja anulowana")
    }
    
    // W zakresie, gdzie zdefiniowano cancellable, przy wyjściu zostanie wywołane cancel()
    
  3. Anulowanie w Combine: W frameworku Combine większość Publisherów zapewnia subskrypcję (Subscription), która implementuje protokół Cancellable. Po wywołaniu cancel() na Subscription, strumień danych zostaje zatrzymany. Zazwyczaj Subscription jest opakowany w AnyCancellable i przechowywany.

    // Przykład w Combine
    import Combine
    
    let publisher = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var cancellable: AnyCancellable? = publisher.sink { completion in
        print("Zakończenie: \(completion)")
    } receiveValue: { date in
        print("Wartość: \(date)")
    }
    
    // Anulowanie po pewnym czasie
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        cancellable?.cancel() // Wywołanie cancel() na `AnyCancellable`
        cancellable = nil // Czyszczenie referencji
    }
    
  4. Operation i OperationQueue: W starszych API istnieje również mechanizm anulowania. Klasa Operation ma metodę cancel() i właściwość isCancelled. OperationQueue sprawdza tę właściwość i nie planuje wykonania anulowanych operacji.

    import Foundation
    
    class MyOperation: Operation {
        override func main() {
            if isCancelled { // Sprawdzenie statusu anulowania
                print("Operacja anulowana przed rozpoczęciem")
                return
            }
    
            // Wykonanie zadania
            for i in 0..<1000 {
                if isCancelled { // Sprawdzenie statusu podczas zadania
                    print("Operacja anulowana podczas wykonywania")
                    return
                }
                // Ciężka praca lub wywołanie API
                print("Krok \(i)")
            }
    
            print("Operacja zakończona")
        }
    }
    
    let queue = OperationQueue()
    let operation = MyOperation()
    
    queue.addOperation(operation)
    
    // Anulowanie operacji po pewnym czasie
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
       operation.cancel() // Wywołanie cancel()
    }
    
    // Oczekiwanie na zakończenie (niezalecane na głównym wątku)
    // queue.waitUntilAllOperationsAreFinished()
    

Mechanizm anulowania w iOS jest asynchroniczny i kooperatywny. Wywołanie cancel() sygnalizuje zamiar anulowania operacji/strumienia danych, ale faktyczne zatrzymanie zależy od tego, jak sama operacja obsługuje ten sygnał (np. sprawdzając isCancelled lub reagując na anulowanie subskrypcji).

Zarządzanie obiektami możliwymi do anulowania (zwłaszcza AnyCancellable) często odbywa się przez ich przechowywanie w kolekcjach (Set<AnyCancellable>) lub właściwościach obiektów, aby zapewnić wywołanie cancel() przy deinitializacji kontenera lub jego jawnym usunięciu z kolekcji.