Ricerca…


Sintassi

  • Swift 3.0

  • DispatchQueue.main // Ottieni la coda principale

  • DispatchQueue (label: "my-serial-queue", attributi: [.serial, .qosBackground]) // Crea la tua coda seriale privata

  • DispatchQueue.global (attributi: [.qosDefault]) // Accede a una delle code simultanee globali

  • DispatchQueue.main.async {...} // Invia un'attività in modo asincrono al thread principale

  • DispatchQueue.main.sync {...} // Invia un'attività in modo sincrono al thread principale

  • DispatchQueue.main.asyncAfter (deadline: .now () + 3) {...} // Invio di un'attività in modo asincrono al thread principale da eseguire dopo x secondi

  • Swift <3.0

  • dispatch_get_main_queue () // Ottieni la coda principale in esecuzione sul thread principale

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Ottieni la coda globale con priorità specificata dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Void in ...} // Invio di un'attività in modo asincrono sul dispatch_queue_t specificato

  • dispatch_sync (dispatch_queue_t) {() -> Void in ...} // Invio di un'attività in modo sincrono sulla dispatch_queue_t specificata

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (nanoseconds)), dispatch_queue_t, {...}); // Invio di un'attività su dispatch_queue_t specificato dopo nanosecondi

Ottenere una coda Grand Central Dispatch (GCD)

Grand Central Dispatch lavora sul concetto di "Dispatch Queues". Una coda di invio esegue le attività designate nell'ordine in cui sono state inoltrate. Esistono tre tipi di code di invio:

  • Le code di invio seriale (ovvero le code di invio private) eseguono un compito alla volta, in ordine. Sono spesso utilizzati per sincronizzare l'accesso a una risorsa.
  • Le code simultanee di invio (ovvero le code di invio globali) eseguono contemporaneamente una o più attività.
  • La Main Dispatch Queue esegue le attività sul thread principale.

Per accedere alla coda principale:

3.0
let mainQueue = DispatchQueue.main
3.0
let mainQueue = dispatch_get_main_queue()

Il sistema fornisce code di invio globali simultanee (globali all'applicazione), con priorità diverse. Puoi accedere a queste code usando la classe DispatchQueue in Swift 3:

3.0
let globalConcurrentQueue = DispatchQueue.global(qos: .default)

equivalente a

let globalConcurrentQueue = DispatchQueue.global()
3.0
let globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

In iOS 8 o versioni successive, la possibile qualità dei valori di servizio che possono essere passati sono .userInteractive , .userInitiated , .default , .utility e .background . Sostituiscono le costanti DISPATCH_QUEUE_PRIORITY_ .

Puoi anche creare le tue code con priorità diverse:

3.0
let myConcurrentQueue = DispatchQueue(label: "my-concurrent-queue", qos: .userInitiated, attributes: [.concurrent], autoreleaseFrequency: .workItem, target: nil)
let mySerialQueue = DispatchQueue(label: "my-serial-queue", qos: .background, attributes: [], autoreleaseFrequency: .workItem, target: nil)
3.0
let myConcurrentQueue = dispatch_queue_create("my-concurrent-queue", DISPATCH_QUEUE_CONCURRENT)
let mySerialQueue = dispatch_queue_create("my-serial-queue", DISPATCH_QUEUE_SERIAL)

In Swift 3, le code create con questo inizializzatore sono di serie per impostazione predefinita e il passaggio .workItem per la frequenza di autorelease garantisce che un pool di autorelease venga creato e scaricato per ciascun elemento di lavoro. C'è anche. .never , il che significa che gestirai i tuoi pool di autorilease autonomamente, o. .inherit che eredita l'impostazione dall'ambiente. Nella maggior parte dei casi probabilmente non lo userai .never tranne nei casi di estrema personalizzazione.

Esecuzione di attività in una coda Grand Central Dispatch (GCD)

3.0

Per eseguire attività su una coda di invio, utilizzare i metodi sync , async e after .

Per inviare un'attività a una coda in modo asincrono:

let queue = DispatchQueue(label: "myQueueName")

queue.async {
    //do something
    
    DispatchQueue.main.async {
        //this will be called in main thread
        //any UI updates should be placed here
    }
}
// ... code here will execute immediately, before the task finished

Per inviare un'attività a una coda in modo sincrono:

queue.sync {
    // Do some task
}
// ... code here will not execute until the task is finished

Per inviare un'attività in una coda dopo un determinato numero di secondi:

queue.asyncAfter(deadline: .now() + 3) {
    //this will be executed in a background-thread after 3 seconds
}
// ... code here will execute immediately, before the task finished

NOTA: Eventuali aggiornamenti dell'interfaccia utente dovrebbero essere richiamati sul thread principale! Assicurati di inserire il codice per gli aggiornamenti dell'interfaccia utente all'interno di DispatchQueue.main.async { ... }

2.0

Tipi di coda:

let mainQueue = dispatch_get_main_queue()
let highQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
let backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

Per inviare un'attività a una coda in modo asincrono:

dispatch_async(queue) {
    // Your code run run asynchronously. Code is queued and executed 
    // at some point in the future.
}
// Code after the async block will execute immediately

Per inviare un'attività a una coda in modo sincrono:

dispatch_sync(queue) {
    // Your sync code
}
// Code after the sync block will wait until the sync task finished

Per inviare un'attività dopo un intervallo di tempo (utilizzare NSEC_PER_SEC per convertire secondi in nanosecondi):

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    // Code to be performed in 2.5 seconds here
}

Per eseguire un'attività in modo asincrono e aggiornare l'interfaccia utente:

dispatch_async(queue) {
    // Your time consuming code here
    dispatch_async(dispatch_get_main_queue()) {
        // Update the UI code 
    }
}

NOTA: Eventuali aggiornamenti dell'interfaccia utente dovrebbero essere richiamati sul thread principale! Assicurati di aver inserito il codice per gli aggiornamenti dell'interfaccia utente all'interno di dispatch_async(dispatch_get_main_queue()) { ... }

Cicli concomitanti

GCD fornisce un meccanismo per eseguire un ciclo, in cui i cicli si verificano contemporaneamente l'uno rispetto all'altro. Questo è molto utile quando si eseguono una serie di calcoli computazionalmente costosi.

Considera questo ciclo:

for index in 0 ..< iterations {
    // Do something computationally expensive here
}

È possibile eseguire questi calcoli contemporaneamente utilizzando concurrentPerform (in Swift 3) o dispatch_apply (in Swift 2):

3.0
DispatchQueue.concurrentPerform(iterations: iterations) { index in
    // Do something computationally expensive here
}
3.0
dispatch_apply(iterations, queue) { index in
    // Do something computationally expensive here
}

La chiusura del ciclo sarà invocata per ogni index da 0 a, ma non incluse, iterations . Queste iterazioni verranno eseguite simultaneamente l'una rispetto all'altra e quindi l'ordine che esse eseguono non è garantito. Il numero effettivo di iterazioni che si verificano simultaneamente in un dato momento è generalmente dettato dalle capacità del dispositivo in questione (ad esempio quanti core ha il dispositivo).

Un paio di considerazioni speciali:

  • Il concurrentPerform / dispatch_apply può eseguire i loop simultaneamente l'uno rispetto all'altro, ma tutto avviene in modo sincrono rispetto al thread da cui viene chiamato. Quindi, non chiamarlo dal thread principale, in quanto ciò bloccherà quel thread fino a quando il ciclo non sarà terminato.

  • Poiché questi cicli si verificano contemporaneamente l'uno rispetto all'altro, si è responsabili di garantire la sicurezza del thread dei risultati. Ad esempio, se si aggiornano alcuni dizionari con i risultati di questi calcoli computazionalmente costosi, assicurarsi di sincronizzarli autonomamente.

  • Nota, c'è un sovraccarico associato nell'esecuzione di cicli concomitanti. Pertanto, se i calcoli eseguiti all'interno del ciclo non sono sufficientemente intensi dal punto di vista computazionale, è possibile che le prestazioni ottenute utilizzando loop concomitanti possano essere diminuite, se non completamente compensate, dall'overhead associato alla sincronizzazione di tutti questi thread simultanei.

    Quindi, sei responsabile della determinazione della quantità corretta di lavoro da eseguire in ogni iterazione del ciclo. Se i calcoli sono troppo semplici, puoi usare "striding" per includere più work per loop. Ad esempio, anziché eseguire un ciclo simultaneo con 1 milione di calcoli triviali, è possibile eseguire 100 iterazioni nel ciclo, eseguendo 10.000 calcoli per ciclo. In questo modo viene eseguito abbastanza lavoro su ciascun thread, quindi l'overhead associato alla gestione di questi loop simultanei diventa meno significativo.

Esecuzione di attività in un'operazioneQueue

Puoi pensare a OperationQueue come a una linea di compiti in attesa di essere eseguita. A differenza delle code di invio in GCD, le code di operazioni non sono FIFO (first-in-first-out). Invece, eseguono compiti non appena sono pronti per essere eseguiti, a patto che ci siano abbastanza risorse di sistema per consentirne l'esecuzione.

Ottieni l' OperationQueue principale:

3.0
let mainQueue = OperationQueue.main

Creare un OperationQueue personalizzato:

3.0
let queue = OperationQueue()
queue.name = "My Queue"
queue.qualityOfService = .default

Quality of Service specifica l'importanza del lavoro o quanto l'utente è probabile che contenga risultati immediati dall'attività.

Aggiungere un Operation ad un OperationQueue :

3.0
// An instance of some Operation subclass
let operation = BlockOperation {
    // perform task here
}

queue.addOperation(operation)

Aggiungi un blocco a OperationQueue :

3.0
myQueue.addOperation {
    // some task
}

Aggiungere più Operation s a OperationQueue :

3.0
let operations = [Operation]()
// Fill array with Operations

myQueue.addOperation(operations)

Regola il numero di Operation che possono essere eseguite contemporaneamente all'interno della coda:

myQueue.maxConcurrentOperationCount = 3 // 3 operations may execute at once

// Sets number of concurrent operations based on current system conditions
myQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount

La sospensione di una coda impedirà l'avvio dell'esecuzione di qualsiasi operazione esistente, non avviata o di qualsiasi nuova operazione aggiunta alla coda. Il modo per riprendere questa coda è di impostare isSuspended su false :

3.0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

Sospensione di OperationQueue non si ferma o annullare operazioni che sono già in esecuzione. Si dovrebbe tentare solo di sospendere una coda che è stata creata, non le code globali o la coda principale.

Creazione di operazioni di alto livello

Il framework Foundation fornisce il tipo di Operation , che rappresenta un oggetto di alto livello che incapsula una porzione di lavoro che può essere eseguita su una coda. La coda non solo coordina le prestazioni di tali operazioni, ma è anche possibile stabilire dipendenze tra operazioni, creare operazioni cancellabili, limitare il grado di concorrenza utilizzato dalla coda di operazioni, ecc.

Operation s sono pronte per essere eseguite al termine dell'esecuzione di tutte le sue dipendenze. La proprietà isReady cambia in true .

Creare una sottoclasse Operation non simultanea semplice:

3.0
class MyOperation: Operation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}
2.3
class MyOperation: NSOperation {

    init(<parameters>) {
        // Do any setup work here
    }

    override func main() {
        // Perform the task
    }

}

Aggiungi un'operazione a un OperationQueue :

1.0
myQueue.addOperation(operation)

Questo eseguirà l'operazione contemporaneamente in coda.

Gestire le dipendenze su un Operation .

Le dipendenze definiscono altre Operation che devono essere eseguite su una coda prima che l' Operation sia considerata pronta per l'esecuzione.

1.0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Eseguire un Operation senza una coda:

1.0
   operation.start()

Le dipendenze saranno ignorate. Se si tratta di un'operazione simultanea, l'attività può ancora essere eseguita contemporaneamente se il suo metodo di start scarica da lavoro alle code in background.

Operazioni simultanee.

Se il compito che l' Operation è da eseguire è, a sua volta, asincrono, (ad esempio un URLSession compito dati), è necessario implementare l' Operation come un'operazione simultanea. In questo caso, l'implementazione isAsynchronous deve restituire true , in genere è necessario start metodo che esegue alcune impostazioni, quindi chiama il suo metodo main che esegue effettivamente l'attività.

Quando si implementa un asincrono Operation inizia è necessario implementare isExecuting , isFinished metodi e KVO. Pertanto, quando viene avviata l'esecuzione, isExecuting property cambia in true . Quando un Operation termina il suo compito, isExecuting è impostato su false , e isFinished è impostata su true . Se l'operazione è annullata, isCancelled e isFinished cambiano in true . Tutte queste proprietà sono osservabili come valori chiave.

Annullamento di un Operation .

Chiamando cancel cambia semplicemente la proprietà isCancelled su true . Per rispondere alla cancellazione dalla propria sottoclasse Operation , è necessario verificare il valore di isCancelled almeno periodicamente all'interno di main e rispondere in modo appropriato.

1.0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow