OperationQueue este o coadă de sarcini de nivel înalt în iOS și macOS, construită deasupra Grand Central Dispatch. Conform Apple Developer Documentation, 2026, OperationQueue gestionează instanțele Operation — obiecte care încapsulează o unitate de lucru. Spre deosebire de DispatchQueue, OperationQueue suportă dependențe între operații, priorități, observare KVO și anularea sarcinilor lansate. OperationQueue gestionează automat pool-ul de fire de execuție, distribuind operațiile în funcție de resursele disponibile ale sistemului.
Principalele puncte
OperationQueue este o clasă din framework-ul Foundation care gestionează executarea obiectelor Operation. Spre deosebire de DispatchQueue, OperationQueue nu necesită specificarea explicită a modului serial sau concurrent — numărul de operații executate simultan este reglat de proprietatea maxConcurrentOperationCount. Valoarea 1 transformă coada în sequential, orice altă valoare — în concurrent.
Operation este o clasă abstractă care reprezintă o unitate de lucru. Fiecare operație are o stare: ready, executing, finished sau cancelled. Stările sunt compatibile cu KVO (Key-Value Observing), ceea ce permite reacția la schimbări — de exemplu, actualizarea UI la finalizarea operației. Operation gestionează automat flag-urile isExecuting și isFinished.
Conform Apple (2026), OperationQueue folosește GCD sub capotă, dar adaugă funcționalități indisponibile în DispatchQueue: dependențe, priorități și anularea operațiilor. Dacă aplicația trece în fundal, OperationQueue suspendă execuția, iar la revenire — o reia. OperationQueue de asemenea ia automat în considerare numărul de nuclee ale procesorului și alege numărul optim de fire de execuție.
Fiecare operație trece prin patru stări: pending (așteptare), ready (gata de lansare), executing (în execuție) și finished (finalizată). Starea cancelled poate apărea în orice etapă înainte de finalizare. Tranzițiile între stări sunt urmărite prin KVO — aceasta este baza actualizării reactive a UI. OperationQueue elimină automat operațiile finalizate din coadă și notifică operațiile dependente că precondiția lor a fost îndeplinită, inițiind execuția lor.
Operation este o clasă abstractă care necesită suprascrierea metodei main() sau start(). În metoda main() se plasează codul sarcinii, iar starea isExecuting și isFinished sunt gestionate automat. Pentru operații asincrone este necesară suprascrierea start() și gestionarea manuală a flag-urilor de stare.
BlockOperation este o implementare concretă a Operation care execută unul sau mai multe blocuri de cod. BlockOperation devine concurrent dacă se adaugă mai multe blocuri prin addExecutionBlock(). Operația se finalizează doar după executarea tuturor blocurilor adăugate. BlockOperation este o alternativă convenabilă pentru sarcini simple fără moștenire.
| Caracteristică | Operation | BlockOperation |
|---|---|---|
| Tip clasă | Abstractă | Concretă |
| Moștenire | Necesară | Nu este necesară |
| Asincronism | Gestionare manuală KVO | Automată |
| Blocuri de cod | Unul în main() | Unul sau mai multe |
| Aplicație | Sarcini complexe cu stare | Sarcini simple unice |
| Potrivit pentru | Dependențe, anulare, progres | Blocuri rapide, completion |
| Memorie | Mai mare din cauza KVO și stării | Minimă, ușoară |
Pentru a crea o operație personalizată, moșteniți de la Operation și suprascrieți main(). În interior, verificați flag-ul isCancelled înaintea operațiilor costisitoare pentru a asigura o anulare rapidă. Acest lucru este critic pentru descărcarea fișierelor mari sau procesarea în lot a datelor. Alegerea între Operation și BlockOperation depinde de complexitatea sarcinii: pentru acțiuni simple unice este suficient BlockOperation, pentru logică reutilizabilă cu stare — moștenirea de la Operation.
Dependențele reprezintă avantajul cheie al OperationQueue față de DispatchQueue. Metoda addDependency(_:) specifică faptul că operația B se execută doar după finalizarea operației A. Dependențele formează un directed acyclic graph (DAG): la adăugarea unei dependențe ciclice, coada o ignoră, iar operațiile nu sunt lansate.
Prioritatea operației se setează prin proprietatea queuePriority cu valorile: .veryLow, .low, .normal, .high, .veryHigh. Prioritatea influențează ordinea de lansare între operațiile ready, dar nu înlocuiește dependențele. OperationQueue ia în considerare mai întâi dependențele, apoi prioritatea între operațiile disponibile.
Scenariu tipic — încărcarea datelor de profil: mai întâi încărcăm utilizatorul, apoi pe baza id-ului său încărcăm prietenii și postările. Setarea dependenței între încărcarea utilizatorului și încărcarea prietenilor garantează ordinea corectă fără completion handler imbricate.
Proprietatea maxConcurrentOperationCount limitează numărul de operații executate simultan. Valoarea 1 creează o coadă sequential, valoarea implicită (NSOperationQueueDefaultMaxConcurrentOperationCount) — optimă sistemic, dependentă de încărcarea curentă a dispozitivului. Setarea corectă a acestui parametru previne consumul excesiv de resurse: pentru încărcarea imaginilor sunt suficiente 4-6 operații concurrent, pentru sarcini CPU-intensive — numărul de nuclee ale procesorului.
Alegerea între OperationQueue și DispatchQueue depinde de complexitatea sarcinii. DispatchQueue este un instrument ușor pentru apeluri async simple. OperationQueue este o soluție mai grea pentru scenarii complexe cu multiple sarcini interdependente. Apple recomandă începerea cu DispatchQueue și trecerea la OperationQueue doar când sunt necesare dependențe sau anulare. Pentru majoritatea proiectelor iOS, combinația ambelor instrumente oferă un echilibru optim între performanță și flexibilitate.
Conform Ray Wenderlich (2025), în proiectele iOS mari, OperationQueue este folosită pentru încărcarea conținutului cu progres și anulare, iar DispatchQueue — pentru toate celelalte operații async. Raportul este de aproximativ 20 la 80 în favoarea DispatchQueue.
Să examinăm trei exemple: un BlockOperation simplu, o Operation personalizată cu dependențe și o operație anulabilă pentru încărcarea datelor.
Cel mai simplu caz — executați un bloc pe OperationQueue și procesați rezultatul prin completionBlock. Fiecare Operation are o proprietate încorporată completionBlock, apelată după finalizarea main().
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
Dependența garantează că parseOperation pornește doar după finalizarea downloadOperation. Aceasta elimină necesitatea callback-urilor imbricate.
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
Suprascrieți main() cu verificarea periodică a isCancelled. Aceasta permite oprirea imediată a operației la anulare, fără a aștepta finalizarea operației costisitoare.
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) }
}
}
Anularea operației setează flag-ul isCancelled la true, dar nu oprește metoda main() deja lansată. Codul din interiorul main() trebuie să verifice independent isCancelled și să se încheie la nevoie. Aceasta este o decizie arhitecturală Apple — care permite dezvoltatorului să elibereze corect resursele la anulare.
Observarea KVO a proprietăților isFinished și isExecuting permite reacția la finalizarea operațiilor fără callback explicit. OperationQueue elimină automat operațiile finalizate din coadă, dar acestea rămân în memorie atâta timp cât există referințe puternice. KVO stă la baza integrării OperationQueue cu framework-uri reactive precum RxSwift sau Combine.
Abonarea la isCancelled prin KVO permite actualizarea UI la anularea operației — de exemplu, afișarea unui placeholder în locul încărcării anulate. Proprietatea isCancelled este compatibilă KVO, ceea ce o face convenabilă pentru pipeline-uri reactive.
Nu creați operații în număr mare — fiecare Operation este un obiect separat în memorie. Dacă sarcina este scurtă și nu necesită dependențe, folosiți DispatchQueue direct. OperationQueue este justificată doar pentru scenarii complexe cu dependențe explicite, anulare și monitorizare a progresului.
Verificați isCancelled înaintea operațiilor costisitoare în interiorul metodei main(). În cazul descărcării fișierelor sau procesării imaginilor, verificarea după fiecare pas semnificativ asigură un răspuns rapid la anulare. Folosiți if isCancelled { return } la începutul main() și după fiecare operație mare.
Gestionați corect completionBlock. Proprietatea completionBlock a operației este apelată după finalizarea main(), chiar dacă operația a fost anulată. Verificați isCancelled în interiorul completionBlock pentru a nu actualiza UI cu date eronate. OperationQueue.main — o coadă thread-safe pentru operații UI, analogă cu DispatchQueue.main.
Evitați dependențele ciclice — ele duc la situația în care niciuna dintre operațiile din ciclu nu se va lansa vreodată. OperationQueue nu detectează automat ciclurile: dacă A depinde de B, iar B depinde de A, ambele rămân pentru totdeauna în starea ready. Planificați graful de dependențe din timp.
Întrebări frecvente
OperationQueue este construită deasupra GCD și adaugă dependențe, priorități, KVO și anularea operațiilor. DispatchQueue este un instrument mai ușor pentru sarcini async simple, fără aceste capacități.
Setați proprietatea maxConcurrentOperationCount la 1. Aceasta transformă OperationQueue într-o coadă sequential, păstrând toate avantajele — dependențe, priorități și anulare.
Metoda cancel() setează flag-ul isCancelled, dar nu oprește metoda main() aflată în execuție. Codul operației trebuie să verifice singur isCancelled și să se încheie. Anularea funcționează doar pentru operațiile pending și ready.
Operația trebuie moștenită atunci când este necesară gestionarea stării, asincronismul sau reutilizarea logicii. BlockOperation este potrivită pentru sarcini simple unice, fără moștenire.
Nu, cu excepția cazului în care metoda waitUntilFinished este apelată cu parametrul true pe firul principal. Operațiile se execută implicit pe fire de fundal, iar rezultatul este returnat prin OperationQueue.main.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și