OperationQueue — ce este, Operation și gestionarea sarcinilor

Autor: IT Sectr Publicat: 2026-03-16 Timp de citire: 8 min

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 — coadă de nivel înalt cu suport pentru dependențe între operații
  • Operation — clasă abstractă pentru încapsularea unei unități de lucru cu stare
  • BlockOperation — implementare simplificată a Operation pentru un singur bloc de cod
  • Dependențele determină ordinea de execuție: operația B pornește după A
  • Anularea operațiilor este suportată prin proprietatea isCancelled compatibilă KVO

Ce este OperationQueue și Operation

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.

Ciclul de viață al Operation

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 și BlockOperation: implementarea sarcinilor

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ăOperationBlockOperation
Tip clasăAbstractăConcretă
MoștenireNecesarăNu este necesară
AsincronismGestionare manuală KVOAutomată
Blocuri de codUnul în main()Unul sau mai multe
AplicațieSarcini complexe cu stareSarcini simple unice
Potrivit pentruDependențe, anulare, progresBlocuri rapide, completion
MemorieMai mare din cauza KVO și stăriiMinimă, ușoară

Crearea unei Operation personalizate

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țe și priorități ale operațiilor

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.

Exemplu practic de dependențe

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.

Limitarea paralelismului

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.

OperationQueue vs DispatchQueue: comparație

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.

  • DispatchQueue — ușoară, rapidă, fără overhead-ul obiectelor Operation
  • OperationQueue — suportă dependențe, anulare, KVO și priorități
  • DispatchQueue — ideală pentru sarcini simple async/asyncAfter și sincronizare prin serial
  • OperationQueue — indispensabilă pentru algoritmi pas cu pas cu etape secvențiale
  • DispatchQueue — integrare cu Swift Concurrency (async/await) prin Continuation

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.

Exemple de cod cu OperationQueue în Swift

Să examinăm trei exemple: un BlockOperation simplu, o Operation personalizată cu dependențe și o operație anulabilă pentru încărcarea datelor.

BlockOperation cu completion

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().

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

Dependențe între operații

Dependența garantează că parseOperation pornește doar după finalizarea downloadOperation. Aceasta elimină necesitatea callback-urilor imbricate.

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

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

Operație personalizată anulabilă

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.

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) }
    }
}

Anularea operațiilor și observarea KVO

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.

Gestionarea anulării prin KVO

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.

Cele mai bune practici de lucru cu OperationQueue

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

Cu ce se deosebește OperationQueue de DispatchQueue?

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.

Cum se face coada secvențială?

Setați proprietatea maxConcurrentOperationCount la 1. Aceasta transformă OperationQueue într-o coadă sequential, păstrând toate avantajele — dependențe, priorități și anulare.

Se poate anula o operație deja lansată?

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.

Când să folosiți Operation în loc de BlockOperation?

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.

Blochează OperationQueue firul principal?

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

  • OperationQueue — coadă de nivel înalt cu dependențe, priorități și anularea operațiilor
  • Operation — clasă abstractă pentru încapsularea muncii cu stare compatibilă KVO
  • BlockOperation — implementare simplificată pentru unul sau mai multe blocuri de cod
  • Dependențele stabilesc ordinea de execuție între operații printr-un graf fără cicluri
  • Anularea necesită verificarea manuală a isCancelled în interiorul metodei main() a operației
  • maxConcurrentOperationCount = 1 transformă coada în modul sequential
  • OperationQueue vs DispatchQueue — alegeți OperationQueue doar când sunt necesare dependențe sau KVO

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.

Discutați proiectul

Citiți și