OperationQueue — cos'è, Operation e gestione delle attività

Autore: IT Sectr Pubblicato: 2026-03-16 Tempo di lettura: 8 min

OperationQueue è una coda di attività di alto livello in iOS e macOS costruita sopra Grand Central Dispatch. Secondo Apple Developer Documentation, 2026, OperationQueue gestisce istanze di Operation — oggetti che incapsulano un'unità di lavoro. A differenza di DispatchQueue, OperationQueue supporta dipendenze tra operazioni, priorità, osservazione KVO e cancellazione di attività in esecuzione. OperationQueue gestisce automaticamente un pool di thread, distribuendo le operazioni tra le risorse di sistema disponibili.

Punti Chiave

  • OperationQueue — una coda di alto livello con supporto per dipendenze tra operazioni
  • Operation — una classe astratta per incapsulare un'unità di lavoro con stato
  • BlockOperation — un'implementazione semplificata di Operation per un singolo blocco di codice
  • Dipendenze definiscono l'ordine di esecuzione: l'operazione B viene eseguita dopo A
  • Cancellazione delle operazioni è supportata tramite la proprietà isCancelled compatibile con KVO

Cos'è OperationQueue e Operation

OperationQueue è una classe del framework Foundation che gestisce l'esecuzione di oggetti Operation. A differenza di DispatchQueue, OperationQueue non richiede di specificare esplicitamente la modalità seriale o concorrente — il numero di operazioni eseguite simultaneamente è controllato dalla proprietà maxConcurrentOperationCount. Il valore 1 rende la coda sequenziale, qualsiasi altro valore la rende concorrente.

Operation è una classe astratta che rappresenta un'unità di lavoro. Ogni operazione ha uno stato: ready, executing, finished o cancelled. Gli stati sono compatibili con KVO (Key-Value Observing), consentendo di reagire ai cambiamenti — ad esempio, aggiornare l'interfaccia utente al completamento di un'operazione. Operation gestisce automaticamente i flag isExecuting e isFinished.

Secondo Apple (2026), OperationQueue utilizza GCD internamente ma aggiunge funzionalità non disponibili in DispatchQueue: dipendenze, priorità e cancellazione delle operazioni. Se l'app entra in background, OperationQueue sospende l'esecuzione e la riprende al ritorno. OperationQueue considera automaticamente anche il numero di core della CPU e seleziona il numero ottimale di thread.

Ciclo di Vita di una Operation

Ogni operazione attraversa quattro stati: pending (in attesa), ready (pronta), executing (in esecuzione) e finished (completata). Lo stato cancelled può verificarsi in qualsiasi fase prima del completamento. Le transizioni di stato vengono tracciate tramite KVO — questa è la base per gli aggiornamenti reattivi dell'interfaccia. OperationQueue rimuove automaticamente le operazioni completate dalla coda e notifica alle operazioni dipendenti che il loro prerequisito è stato soddisfatto, attivandone l'esecuzione.

Operation e BlockOperation: Implementazione delle Attività

Operation è una classe astratta che richiede la sovrascrittura del metodo main() o start(). Il codice dell'attività viene inserito nel metodo main(), e gli stati isExecuting e isFinished vengono gestiti automaticamente. Per le operazioni asincrone, è necessario sovrascrivere start() e gestire manualmente i flag di stato.

BlockOperation è un'implementazione concreta di Operation che esegue uno o più blocchi di codice. BlockOperation diventa concorrente se si aggiungono più blocchi tramite addExecutionBlock(). L'operazione viene completata solo dopo l'esecuzione di tutti i blocchi aggiunti. BlockOperation è un'alternativa conveniente per attività semplici senza ereditarietà.

CaratteristicaOperationBlockOperation
Tipo di ClasseAstrattaConcreta
EreditarietàRichiestaNon richiesta
AsincroniaGestione manuale KVOAutomatica
Blocchi di CodiceUno in main()Uno o più
UtilizzoAttività complesse con statoAttività semplici una tantum
Adatto perDipendenze, cancellazione, progressoBlocchi rapidi, completamento
MemoriaPiù alta a causa di KVO e statoMinima, leggera

Creazione di una Operation Personalizzata

Per creare un'operazione personalizzata, ereditare da Operation e sovrascrivere main(). All'interno, verificare il flag isCancelled prima di operazioni costose per garantire una cancellazione rapida. Questo è critico per il download di file di grandi dimensioni o l'elaborazione batch di dati. La scelta tra Operation e BlockOperation dipende dalla complessità dell'attività: per azioni semplici una tantum, BlockOperation è sufficiente; per logica riutilizzabile con stato, ereditare da Operation.

Dipendenze e Priorità delle Operazioni

Le dipendenze sono il vantaggio principale di OperationQueue rispetto a DispatchQueue. Il metodo addDependency(_:) specifica che l'operazione B viene eseguita solo dopo il completamento dell'operazione A. Le dipendenze formano un grafo diretto aciclico (DAG): se viene aggiunta una dipendenza ciclica, la coda la ignora e le operazioni non vengono avviate.

La priorità di un'operazione viene impostata tramite la proprietà queuePriority con valori: .veryLow, .low, .normal, .high, .veryHigh. La priorità influenza l'ordine di avvio tra le operazioni pronte ma non sostituisce le dipendenze. OperationQueue prima risolve le dipendenze, poi applica la priorità tra le operazioni disponibili.

Esempio Pratico di Dipendenze

Uno scenario tipico — caricamento dei dati del profilo: prima caricare l'utente, poi in base al suo id caricare amici e post. Impostare una dipendenza tra caricare l'utente e caricare gli amici garantisce l'ordine corretto senza gestori di completamento annidati.

Limitazione della Concorrenza

La proprietà maxConcurrentOperationCount limita il numero di operazioni eseguite simultaneamente. Il valore 1 crea una coda sequenziale, il valore predefinito (NSOperationQueueDefaultMaxConcurrentOperationCount) è ottimale per il sistema e dipende dal carico corrente del dispositivo. La configurazione corretta di questo parametro previene il consumo eccessivo di risorse: per il caricamento di immagini, 4–6 operazioni concorrenti sono sufficienti; per attività intensive di CPU, utilizzare il numero di core del processore.

OperationQueue vs DispatchQueue: Confronto

La scelta tra OperationQueue e DispatchQueue dipende dalla complessità dell'attività. DispatchQueue è uno strumento leggero per semplici chiamate asincrone. OperationQueue è una soluzione più pesante per scenari complessi con molte attività interconnesse. Apple consiglia di iniziare con DispatchQueue e passare a OperationQueue solo quando sono necessarie dipendenze o cancellazione. Per la maggior parte dei progetti iOS, una combinazione di entrambi gli strumenti offre un equilibrio ottimale tra prestazioni e flessibilità.

  • DispatchQueue — leggero, veloce, senza l'overhead degli oggetti Operation
  • OperationQueue — supporta dipendenze, cancellazione, KVO e priorità
  • DispatchQueue — ideale per semplici attività async/asyncAfter e sincronizzazione seriale
  • OperationQueue — indispensabile per algoritmi passo-passo con fasi sequenziali
  • DispatchQueue — si integra con Swift Concurrency (async/await) tramite Continuation

Secondo Ray Wenderlich (2025), nei grandi progetti iOS, OperationQueue viene utilizzato per caricare contenuti con progresso e cancellazione, mentre DispatchQueue viene utilizzato per tutte le altre operazioni asincrone. Il rapporto è di circa 20 a 80 a favore di DispatchQueue.

Esempi di Codice con OperationQueue in Swift

Vediamo tre esempi: un semplice BlockOperation, una Operation personalizzata con dipendenze e un'operazione annullabile per il caricamento dei dati.

BlockOperation con Completamento

Il caso più semplice — eseguire un blocco su OperationQueue e gestire il risultato tramite completionBlock. Ogni Operation ha una proprietà completionBlock incorporata, chiamata dopo la fine di main().

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

Dipendenze Tra Operazioni

La dipendenza garantisce che parseOperation venga avviata solo dopo il completamento di downloadOperation. Ciò elimina la necessità di callback annidati.

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

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

Operazione Personalizzata Annullabile

Sovrascrivere main() con controlli periodici di isCancelled. Ciò consente all'operazione di fermarsi immediatamente al momento dell'annullamento, senza attendere il completamento di un'operazione costosa.

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

Cancellazione delle Operazioni e Osservazione KVO

La cancellazione di un'operazione imposta il flag isCancelled su true, ma non ferma il metodo main() già in esecuzione. Il codice all'interno di main() deve verificare isCancelled da solo e terminare quando necessario. Questa è una decisione architetturale di Apple — che consente allo sviluppatore di rilasciare correttamente le risorse in caso di annullamento.

L'osservazione KVO delle proprietà isFinished e isExecuting consente di reagire al completamento delle operazioni senza callback espliciti. OperationQueue rimuove automaticamente le operazioni completate dalla coda, ma rimangono in memoria finché ci sono riferimenti forti ad esse. KVO è la base per integrare OperationQueue con framework reattivi come RxSwift o Combine.

Gestione della Cancellazione tramite KVO

Sottoscriversi a isCancelled tramite KVO consente di aggiornare l'interfaccia utente al momento dell'annullamento di un'operazione — ad esempio, mostrare un segnaposto invece di un download annullato. La proprietà isCancelled è compatibile con KVO, rendendola conveniente per pipeline reattive.

Buone Pratiche per Lavorare con OperationQueue

Non creare grandi quantità di operazioni — ogni Operation è un oggetto separato in memoria. Se un'attività è breve e non richiede dipendenze, utilizzare DispatchQueue direttamente. OperationQueue è giustificata per scenari complessi con dipendenze esplicite, cancellazione e monitoraggio del progresso.

Verificare isCancelled prima di operazioni costose all'interno del metodo main(). In caso di download di file o elaborazione di immagini, verificare dopo ogni passaggio significativo garantisce una risposta rapida all'annullamento. Utilizzare if isCancelled { return } all'inizio di main() e dopo ogni operazione importante.

Gestire completionBlock correttamente. La proprietà completionBlock di un'operazione viene chiamata dopo la fine di main(), anche se l'operazione è stata annullata. Verificare isCancelled all'interno di completionBlock per evitare di aggiornare l'interfaccia con dati errati. OperationQueue.main è una coda thread-safe per le operazioni dell'interfaccia, simile a DispatchQueue.main.

Evitare dipendenze cicliche — impediscono l'avvio di qualsiasi operazione nel ciclo. OperationQueue non rileva automaticamente i cicli: se A dipende da B e B dipende da A, entrambe rimarranno per sempre nello stato ready. Pianificare il grafo delle dipendenze in anticipo.

Domande Frequenti

In cosa OperationQueue differisce da DispatchQueue?

OperationQueue è costruito su GCD e aggiunge dipendenze, priorità, KVO e cancellazione delle operazioni. DispatchQueue è uno strumento più leggero per attività asincrone semplici senza queste capacità.

Come rendere la coda sequenziale?

Impostare la proprietà maxConcurrentOperationCount su 1. Questo trasforma OperationQueue in una coda sequenziale mantenendo tutti i vantaggi — dipendenze, priorità e cancellazione.

Si può annullare un'operazione in esecuzione?

Il metodo cancel() imposta il flag isCancelled ma non ferma il metodo main() in esecuzione. Il codice dell'operazione deve verificare isCancelled da solo e terminare. La cancellazione funziona solo per le operazioni in attesa e pronte.

Quando dovrei usare Operation invece di BlockOperation?

Dovresti ereditare da Operation quando hai bisogno di gestione dello stato, asincronia o riutilizzo della logica. BlockOperation è adatto per attività semplici una tantum senza ereditarietà.

OperationQueue blocca il thread principale?

No, a meno che non si chiami waitUntilFinished con il parametro true sul thread principale. Le operazioni vengono eseguite su thread di background per impostazione predefinita e i risultati vengono restituiti tramite OperationQueue.main.

Riepilogo

  • OperationQueue — una coda di alto livello con dipendenze, priorità e cancellazione delle operazioni
  • Operation — una classe astratta per incapsulare il lavoro con stato compatibile KVO
  • BlockOperation — un'implementazione semplificata per uno o più blocchi di codice
  • Dipendenze definiscono l'ordine di esecuzione tra le operazioni tramite un grafo senza cicli
  • Cancellazione richiede la verifica manuale di isCancelled all'interno del metodo main() dell'operazione
  • maxConcurrentOperationCount = 1 trasforma la coda in modalità sequenziale
  • OperationQueue vs DispatchQueue — scegliere OperationQueue solo quando sono necessarie dipendenze o KVO

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche