OperationQueue to vysokoúrovňová fronta úloh w iOS i macOS, postavená na Grand Central Dispatch. Podle Apple Developer Documentation, 2026, OperationQueue spravuje instance Operation — obiektami enkapsulującymi jednostkę pracy. Na rozdíl od DispatchQueue, OperationQueue podporuje závislosti mezi operacemi, priorytety, KVO i zrušení spuštěných úloh. OperationQueue automaticky spravuje fond vláken, rozděluje operace według dostępnych zasobów systemu.
Nejdůležitější
OperationQueue to třída z frameworku Foundation řídící provádění obiektów Operation. Na rozdíl od DispatchQueue, OperationQueue nevyžaduje explicitní určení trybu serial lub concurrent — liczba jednocześnie wykonywanych operacji jest regulována vlastností maxConcurrentOperationCount. Hodnota 1 mění frontu na sequential, každá jiná — na concurrent.
Operation to abstraktní třída reprezentująca jednostkę pracy. Każda operacja ma stan: ready, executing, finished lub cancelled. Stavy jsou kompatibilní s KVO (Key-Value Observing), co umožňuje reagovat na změny — na przykład aktualizovat UI po dokončení operacji. Operation automaticky spravuje flagami isExecuting i isFinished.
Podle Apple (2026), OperationQueue používá GCD pod kapotou, ale přidává funkcionalitu nedostupné v DispatchQueue: zależności, priorytety i anulowanie operacji. Pokud aplikace přejde do režimu pozadí, OperationQueue pozastaví provádění, a po návratu — obnoví. OperationQueue również automaticky zohledňuje počet jader procesora i vybírá optimální počet vláken.
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 to abstraktní třída 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.
| Cechy | Operation | BlockOperation |
|---|---|---|
| Typ klasy | Abstrakcyjna | Konkretna |
| Dziedziczenie | Wymagane | Niewymagane |
| Asynchroniczność | Ręczne zarządzanie KVO | Automatyczne |
| Bloków kodu | Jeden w main() | Jeden lub więcej |
| Zastosowanie | Złożone zadania ze stanem | Proste jednorazowe zadania |
| Nadaje się do | Zależności, anulowanie, postęp | Szybkie bloki, completion |
| Pamięć | Większa przez KVO i stan | Minimalna, lekka |
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 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.
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.
Właściwość maxConcurrentOperationCount ogranicza počet současně prováděných 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.
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.
Podle 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.
Omówimy trzy przykłady: prosty BlockOperation, niestandardową Operation z zależnościami i anulowalną operację do pobierania danych.
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().
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
Zależność gwarantuje, że parseOperation uruchomi się dopiero po zakończeniu downloadOperation. Eliminuje to potrzebę zagnieżdżonych callback.
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
Nadpisz main() z okresowym sprawdzaniem isCancelled. Pozwala to natychmiast zatrzymać operację przy anulowaniu, bez czekania na zakończenie kosztownej operacji.
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 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.
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.
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
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.
Ustaw właściwość maxConcurrentOperationCount na 1. To zamienia OperationQueue w kolejkę sequential z zachowaniem wszystkich zalet — zależności, priorytetów i anulowania.
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.
Operację warto dziedziczyć, gdy wymagane jest zarządzanie stanem, asynchroniczność lub ponowne użycie logiki. BlockOperation nadaje się do prostych jednorazowych zadań bez dziedziczenia.
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
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také