OperationQueue — co to jest, Operation i zarządzanie zadaniami

Autor: IT Sectr Opublikowano: 2026-03-16 Czas czytania: 8 min

OperationQueue to wysokopoziomowa kolejka zadań w iOS i macOS, zbudowana na bazie Grand Central Dispatch. Według Apple Developer Documentation, 2026, OperationQueue zarządza instancjami Operation — obiektami enkapsulującymi jednostkę pracy. W przeciwieństwie do DispatchQueue, OperationQueue obsługuje zależności między operacjami, priorytety, KVO i anulowanie uruchomionych zadań. OperationQueue automatycznie zarządza pulą wątków, rozdzielając operacje według dostępnych zasobów systemu.

Najważniejsze

  • OperationQueue — wysokopoziomowa kolejka z obsługą zależności między operacjami
  • Operation — abstrakcyjna klasa do enkapsulacji jednostki pracy ze stanem
  • BlockOperation — uproszczona implementacja Operation dla jednego bloku kodu
  • Zależności określają kolejność wykonywania: operacja B uruchamia się po A
  • Anulowanie operacji jest obsługiwane przez KVO-zgodną właściwość isCancelled

Czym jest OperationQueue i Operation

OperationQueue to klasa z frameworka Foundation zarządzająca wykonywaniem obiektów Operation. W przeciwieństwie do DispatchQueue, OperationQueue nie wymaga jawnego określania trybu serial lub concurrent — liczba jednocześnie wykonywanych operacji jest regulowana właściwością maxConcurrentOperationCount. Wartość 1 zamienia kolejkę w sequential, każda inna — w concurrent.

Operation to abstrakcyjna klasa reprezentująca jednostkę pracy. Każda operacja ma stan: ready, executing, finished lub cancelled. Stany są zgodne z KVO (Key-Value Observing), co pozwala reagować na zmiany — na przykład aktualizować UI po zakończeniu operacji. Operation automatycznie zarządza flagami isExecuting i isFinished.

Według Apple (2026), OperationQueue używa GCD pod maską, ale dodaje funkcjonalności niedostępne w DispatchQueue: zależności, priorytety i anulowanie operacji. Jeśli aplikacja przechodzi w tryb tła, OperationQueue wstrzymuje wykonywanie, a po powrocie — wznawia. OperationQueue również automatycznie uwzględnia liczbę rdzeni procesora i wybiera optymalną liczbę wątków.

Cykl życia Operation

Każda operacja przechodzi przez cztery stany: pending (oczekiwanie), ready (gotowa do uruchomienia), executing (wykonywana) i finished (zakończona). Stan cancelled może nastąpić na każdym etapie przed zakończeniem. Przejścia między stanami są śledzone przez KVO — to podstawa reaktywnego aktualizowania UI. OperationQueue automatycznie usuwa zakończone operacje z kolejki i powiadamia zależne operacje, że ich warunek wstępny został spełniony, uruchamiając ich wykonanie.

Operation i BlockOperation: implementacja zadań

Operation to abstrakcyjna klasa wymagająca nadpisania metody main() lub start(). W metodzie main() umieszcza się kod zadania, a stan isExecuting i isFinished są zarządzane automatycznie. Dla operacji asynchronicznych wymagane jest nadpisanie start() i ręczne zarządzanie flagami stanu.

BlockOperation to konkretna implementacja Operation wykonująca jeden lub więcej bloków kodu. BlockOperation staje się concurrent, jeśli dodać do niej kilka bloków przez addExecutionBlock(). Operacja kończy się dopiero po wykonaniu wszystkich dodanych bloków. BlockOperation to wygodna alternatywa dla prostych zadań bez dziedziczenia.

CechyOperationBlockOperation
Typ klasyAbstrakcyjnaKonkretna
DziedziczenieWymaganeNiewymagane
AsynchronicznośćRęczne zarządzanie KVOAutomatyczne
Bloków koduJeden w main()Jeden lub więcej
ZastosowanieZłożone zadania ze stanemProste jednorazowe zadania
Nadaje się doZależności, anulowanie, postępSzybkie bloki, completion
PamięćWiększa przez KVO i stanMinimalna, lekka

Tworzenie własnej Operation

Aby utworzyć niestandardową operację, dziedzicz po Operation i nadpisz main(). Wewnątrz sprawdzaj flagę isCancelled przed kosztownymi operacjami, aby zapewnić szybkie anulowanie. Jest to krytyczne przy pobieraniu dużych plików lub wsadowym przetwarzaniu danych. Wybór między Operation a BlockOperation zależy od złożoności zadania: dla prostych jednorazowych działań wystarczy BlockOperation, dla wielokrotnie używanej logiki ze stanem — dziedziczenie po Operation.

Zależności i priorytety operacji

Zależności to kluczowa zaleta OperationQueue nad DispatchQueue. Metoda addDependency(_:) określa, że operacja B wykonuje się dopiero po zakończeniu operacji A. Zależności tworzą directed acyclic graph (DAG): po dodaniu zależności cyklicznej kolejka ją ignoruje, a operacje nie są uruchamiane.

Priorytet operacji jest ustawiany właściwością queuePriority z wartościami: .veryLow, .low, .normal, .high, .veryHigh. Priorytet wpływa na kolejność uruchamiania wśród ready-operacji, ale nie zastępuje zależności. OperationQueue najpierw uwzględnia zależności, potem — priorytet wśród dostępnych operacji.

Praktyczny przykład zależności

Typowy scenariusz — pobieranie danych profilu: najpierw pobieramy użytkownika, następnie na podstawie jego id pobieramy znajomych i posty. Ustawienie zależności między pobieraniem użytkownika a pobieraniem znajomych gwarantuje prawidłową kolejność bez zagnieżdżonych completion handler.

Ograniczenie równoległości

Właściwość maxConcurrentOperationCount ogranicza liczbę jednocześnie wykonywanych operacji. Wartość 1 tworzy kolejkę sequential, wartość domyślna (NSOperationQueueDefaultMaxConcurrentOperationCount) — optymalna systemowo, zależna od bieżącego obciążenia urządzenia. Prawidłowe ustawienie tego parametru zapobiega nadmiernemu zużyciu zasobów: do pobierania obrazów wystarczy 4-6 concurrent operacji, do zadań CPU-intensywnych — liczba rdzeni procesora.

OperationQueue vs DispatchQueue: porównanie

Wybór między OperationQueue a DispatchQueue zależy od złożoności zadania. DispatchQueue to lekkie narzędzie do prostych wywołań async. OperationQueue to cięższe rozwiązanie dla złożonych scenariuszy z wieloma powiązanymi zadaniami. Apple zaleca zaczynać od DispatchQueue i przechodzić na OperationQueue tylko w razie potrzeby zależności lub anulowania. Dla większości projektów iOS kombinacja obu narzędzi daje optymalny balans wydajności i elastyczności.

  • DispatchQueue — lekka, szybka, bez narzutu na obiekty Operation
  • OperationQueue — obsługuje zależności, anulowanie, KVO i priorytety
  • DispatchQueue — idealna do prostych zadań async/asyncAfter i synchronizacji przez serial
  • OperationQueue — niezastąpiona przy algorytmach krokowych z sekwencyjnymi etapami
  • DispatchQueue — integracja z Swift Concurrency (async/await) przez Continuation

Według Ray Wenderlich (2025), w dużych projektach iOS OperationQueue jest używana do pobierania treści z postępem i anulowaniem, a DispatchQueue — do wszystkich pozostałych operacji async. Stosunek wynosi około 20 do 80 na korzyść DispatchQueue.

Przykłady kodu z OperationQueue w Swift

Omówimy trzy przykłady: prosty BlockOperation, niestandardową Operation z zależnościami i anulowalną operację do pobierania danych.

BlockOperation z completion

Najprostszy przypadek — wykonaj blok na OperationQueue i przetwórz wynik przez completionBlock. Każda Operation ma wbudowaną właściwość completionBlock, wywoływaną po zakończeniu main().

swift
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
    let data = NetworkService.fetchData()
    OperationQueue.main.addOperation {
        self.updateUI(data)
    }
}
queue.addOperation(operation)

Zależności między operacjami

Zależność gwarantuje, że parseOperation uruchomi się dopiero po zakończeniu downloadOperation. Eliminuje to potrzebę zagnieżdżonych callback.

swift
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)

let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)

Anulowalna niestandardowa Operation

Nadpisz main() z okresowym sprawdzaniem isCancelled. Pozwala to natychmiast zatrzymać operację przy anulowaniu, bez czekania na zakończenie kosztownej operacji.

swift
class ImageLoadOperation: Operation {
    override func main() {
        guard !self.isCancelled else { return }
        let image = self.downloadImage()
        guard !self.isCancelled else { return }
        OperationQueue.main.addOperation { self.display(image) }
    }
}

Anulowanie operacji i KVO-observacja

Anulowanie operacji ustawia flagę isCancelled na true, ale nie zatrzymuje już uruchomionej metody main(). Kod wewnątrz main() musi samodzielnie sprawdzać isCancelled i kończyć działanie w razie potrzeby. To architektoniczna decyzja Apple — pozwalająca programiście prawidłowo zwolnić zasoby przy anulowaniu.

KVO-observacja właściwości isFinished i isExecuting pozwala reagować na zakończenie operacji bez explicit callback. OperationQueue automatycznie usuwa zakończone operacje z kolejki, ale pozostają one w pamięci, dopóki istnieją silne referencje. KVO to podstawa integracji OperationQueue z reaktywnymi frameworkami typu RxSwift lub Combine.

Obsługa anulowania przez KVO

Subskrypcja isCancelled przez KVO pozwala aktualizować UI przy anulowaniu operacji — na przykład wyświetlać placeholder zamiast anulowanego pobierania. Właściwość isCancelled jest KVO-zgodna, co czyni ją wygodną dla reaktywnych pipeline.

Najlepsze praktyki pracy z OperationQueue

Nie twórz operacji w dużych ilościach — każda Operation jest osobnym obiektem w pamięci. Jeśli zadanie jest krótkie i nie wymaga zależności, używaj DispatchQueue bezpośrednio. OperationQueue jest uzasadniona dla złożonych scenariuszy z jawnymi zależnościami, anulowaniem i monitorowaniem postępu.

Sprawdzaj isCancelled przed kosztownymi operacjami wewnątrz metody main(). W przypadku pobierania plików lub przetwarzania obrazów sprawdzanie po każdym znaczącym kroku zapewnia szybką odpowiedź na anulowanie. Używaj if isCancelled { return } na początku main() i po każdej dużej operacji.

Prawidłowo zarządzaj completionBlock. Właściwość completionBlock operacji jest wywoływana po zakończeniu main(), nawet jeśli operacja została anulowana. Sprawdzaj isCancelled wewnątrz completionBlock, aby nie aktualizować UI błędnymi danymi. OperationQueue.main — bezpieczna wątkowo kolejka dla operacji UI, analogiczna do DispatchQueue.main.

Unikaj zależności cyklicznych — prowadzą one do tego, że żadna z operacji w cyklu nigdy się nie uruchomi. OperationQueue nie wykrywa cykli automatycznie: jeśli A zależy od B, a B zależy od A, obie na zawsze pozostaną w stanie ready. Planuj graf zależności z wyprzedzeniem.

Często zadawane pytania

Czym OperationQueue różni się od DispatchQueue?

OperationQueue jest zbudowana na GCD i dodaje zależności, priorytety, KVO i anulowanie operacji. DispatchQueue to lżejsze narzędzie do prostych zadań async bez tych możliwości.

Jak zrobić kolejkę sekwencyjną?

Ustaw właściwość maxConcurrentOperationCount na 1. To zamienia OperationQueue w kolejkę sequential z zachowaniem wszystkich zalet — zależności, priorytetów i anulowania.

Czy można anulować uruchomioną operację?

Metoda cancel() ustawia flagę isCancelled, ale nie zatrzymuje wykonującej się metody main(). Kod operacji musi sam sprawdzać isCancelled i kończyć działanie. Anulowanie działa tylko dla pending i ready operacji.

Kiedy warto używać Operation zamiast BlockOperation?

Operację warto dziedziczyć, gdy wymagane jest zarządzanie stanem, asynchroniczność lub ponowne użycie logiki. BlockOperation nadaje się do prostych jednorazowych zadań bez dziedziczenia.

Czy OperationQueue blokuje główny wątek?

Nie, chyba że wywołano metodę waitUntilFinished z parametrem true na głównym wątku. Operacje domyślnie wykonują się na wątkach tła, a wynik jest zwracany przez OperationQueue.main.

Podsumowanie

  • OperationQueue — wysokopoziomowa kolejka z zależnościami, priorytetami i anulowaniem operacji
  • Operation — abstrakcyjna klasa do enkapsulacji pracy z KVO-zgodnym stanem
  • BlockOperation — uproszczona implementacja dla jednego lub wielu bloków kodu
  • Zależności określają kolejność wykonywania między operacjami przez graf bez cykli
  • Anulowanie wymaga ręcznego sprawdzania isCancelled wewnątrz metody main() operacji
  • maxConcurrentOperationCount = 1 zamienia kolejkę w tryb sequential
  • OperationQueue vs DispatchQueue — wybieraj OperationQueue tylko przy potrzebie zależności lub KVO

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również