Sök…


Syntax

  • Swift 3.0

  • DispatchQueue.main // Få huvudkön

  • DispatchQueue (etikett: "my-serial-kö", attribut: [.serial, .qosBackground]) // Skapa din egen privata seriekö

  • DispatchQueue.global (attribut: [.qosDefault]) // Få åtkomst till en av de globala samtidiga köerna

  • DispatchQueue.main.async {...} // Skicka en uppgift asynkront till huvudtråden

  • DispatchQueue.main.sync {...} // Skicka en uppgift synkront till huvudtråden

  • DispatchQueue.main.asyncAfter (tidsfrist:. Nu () + 3) {...} // Skicka en uppgift asynkront till huvudtråden som ska köras efter x sekunder

  • Swift <3.0

  • dispatch_get_main_queue () // Få huvudkön som körs på huvudtråden

  • dispatch_get_global_queue (dispatch_queue_priority_t, 0) // Få global kö med specificerad prioritet dispatch_queue_priority_t

  • dispatch_async (dispatch_queue_t) {() -> Void in ...} // Skicka en uppgift asynkront på det angivna dispatch_queue_t

  • dispatch_sync (dispatch_queue_t) {() -> Void in ...} // Skicka en uppgift synkront på det angivna dispatch_queue_t

  • dispatch_after (dispatch_time (DISPATCH_TIME_NOW, Int64 (nanosekunder)), dispatch_queue_t, {...}); // Skicka en uppgift på det angivna dispatch_queue_t efter nanosekunder

Få en Grand Central Dispatch (GCD) -kö

Grand Central Dispatch arbetar med konceptet "Dispatch Queues". En sändningskö kör uppgifter som du anger i den ordning de skickas. Det finns tre typer av sändningskö:

  • Seriella utsändningsköer (aka privata utsändningsköer) utför en uppgift i taget i ordning. De används ofta för att synkronisera åtkomst till en resurs.
  • Samtidiga sändningsköer (alias globala sändningsköer) utför en eller flera uppgifter samtidigt.
  • Main Dispatch Queue kör uppgifter på huvudtråden.

För att komma åt huvudkön:

3,0
let mainQueue = DispatchQueue.main
3,0
let mainQueue = dispatch_get_main_queue()

Systemet tillhandahåller samtidig globala sändningsköer (globala för din applikation) med olika prioriteringar. Du kan komma åt dessa köer med klassen DispatchQueue i Swift 3:

3,0
let globalConcurrentQueue = DispatchQueue.global(qos: .default)

ekvivalent med

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

I iOS 8 eller senare är den möjliga kvaliteten på servicevärden som kan passeras .userInteractive , .userInitiated , .default , .utility och .background . Dessa ersätter DISPATCH_QUEUE_PRIORITY_ konstanterna.

Du kan också skapa dina egna köer med olika prioriteringar:

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)

I Swift 3 är köer som skapats med denna initierare seriella som standard och passering av .workItem för autoreleasfrekvens säkerställer att en autoreleasepool skapas och dräneras för varje arbetsobjekt. Det finns också .never , vilket innebär att du kommer att hantera dina egna autoreleaspooler själv, eller. .inherit som ärver inställningen från miljön. I de flesta fall kommer du antagligen inte att använda .never utom i fall av extrem anpassning.

Köra uppgifter i en Grand Central Dispatch (GCD) -kö

3,0

För att köra uppgifter i en sändningskö använder du sync , async och after metoder.

Så här skickar du en uppgift till en kö asynkront:

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

Så här skickar du en uppgift till en kö synkront:

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

Så här skickar du en uppgift till en kö efter ett visst antal sekunder:

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

OBS: Eventuella uppdateringar av användargränssnittet ska anropas på huvudtråden! Se till att du lägger in koden för UI-uppdateringar i DispatchQueue.main.async { ... }

2,0

Typer av kö:

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)

Så här skickar du en uppgift till en kö asynkront:

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

Så här skickar du en uppgift till en kö synkront:

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

För att skicka en uppgift till efter ett tidsintervall (använd NSEC_PER_SEC att konvertera sekunder till nanosekunder):

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
}

Så här utför du en uppgift asynkront och uppdaterar gränssnittet:

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

OBS: Eventuella uppdateringar av användargränssnittet ska anropas på huvudtråden! Se till att du lägger in koden för UI-uppdateringar i dispatch_async(dispatch_get_main_queue()) { ... }

Samtidiga öglor

GCD tillhandahåller mekanism för att utföra en slinga, varvid slingorna sker samtidigt med avseende på varandra. Detta är mycket användbart när du gör en serie beräkningar dyra.

Tänk på den här slingan:

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

Du kan utföra dessa beräkningar samtidigt med concurrentPerform (i Swift 3) eller dispatch_apply (i 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
}

Loop-stängningen kommer att påkallas för varje index från 0 till, men inte inkluderande, iterations . Dessa iterationer kommer att köras samtidigt med avseende på varandra, och därmed garanteras inte ordningen att de körs. Det faktiska antalet iterationer som sker samtidigt vid en viss tidpunkt bestäms vanligtvis av kapaciteten hos den aktuella enheten (t.ex. hur många kärnor har enheten).

Ett par speciella överväganden:

  • concurrentPerform / dispatch_apply kan köra slingorna samtidigt med avseende på varandra, men allt detta sker synkront med avseende på tråden från vilken du kallar det. Så ring inte detta från huvudtråden, eftersom det kommer att blockera den tråden tills slingan är klar.

  • Eftersom dessa slingor inträffar samtidigt i förhållande till varandra, är du ansvarig för att säkerställa gängsäkerheten för resultaten. Om du till exempel uppdaterar en viss ordlista med resultaten från dessa beräknings dyra beräkningar, se till att du synkroniserar dessa uppdateringar själv.

  • Observera att det finns en del omkostnader för att köra samtidiga slingor. Om beräkningarna som utförs inuti slingan inte är tillräckligt beräkningsintensiva, kan du upptäcka att alla prestanda som uppnåtts med användning av samtidiga slingor kan minskas, om inte helt kompenseras, av omkostnaderna för att synkronisera alla dessa samtidiga trådar.

    Så du ansvarar för att bestämma rätt mängd arbete som ska utföras i varje iteration av slingan. Om beräkningarna är för enkla kan du använda "steg" för att inkludera mer arbete per slinga. Till exempel, istället för att göra en samtidig loop med 1 miljon triviala beräkningar, kan du göra 100 iterationer i din slinga och göra 10 000 beräkningar per slinga. På det sättet är det tillräckligt med arbete som utförs på varje tråd, så att omkostnaderna för att hantera dessa samtidiga slingor blir mindre betydande.

Köra uppgifter i en OperationQueue

Du kan tänka på en OperationQueue som en rad uppgifter som väntar på att utföras. Till skillnad från avsändningsköer i GCD är operationsköerna inte FIFO (först-in-först-ut). Istället utför de uppgifter så snart de är redo att köras, så länge det finns tillräckligt med systemresurser för att tillåta det.

Få den viktigaste OperationQueue :

3,0
let mainQueue = OperationQueue.main

Skapa en anpassad OperationQueue :

3,0
let queue = OperationQueue()
queue.name = "My Queue"
queue.qualityOfService = .default

Service of Quality specificerar vikten av arbetet, eller hur mycket användaren troligtvis räknar med omedelbara resultat från uppgiften.

Lägg till en Operation till en OperationQueue :

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

queue.addOperation(operation)

Lägg till ett block i en OperationQueue :

3,0
myQueue.addOperation {
    // some task
}

Lägg till flera Operation i en OperationQueue :

3,0
let operations = [Operation]()
// Fill array with Operations

myQueue.addOperation(operations)

Justera hur många Operation kan köras samtidigt i kön:

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

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

Att avbryta en kö förhindrar att den startar exekveringen av befintliga, ostartade operationer eller av några nya åtgärder som läggs till i kön. Sättet att återuppta kön är att ställa in isSuspended tillbaka till false :

3,0
myQueue.isSuspended = true

// Re-enable execution
myQueue.isSuspended = false

Att avbryta en OperationQueue stoppar eller avbryter inte operationer som redan körs. Man bör bara försöka stänga av en kö som du skapade, inte globala köer eller huvudkön.

Skapa operationer på hög nivå

Grundramen tillhandahåller Operation , som representerar ett objekt på hög nivå som kapslar in en del av arbetet som kan utföras i en kö. Kön koordinerar inte bara prestandan för dessa operationer, utan du kan också upprätta beroenden mellan operationer, skapa avbrytbara operationer, begränsa graden av samtidighet som används i operationskön, etc.

Operation blir redo att utföra när alla beroenden har slutförts. isReady ändras sedan till true .

Skapa en enkel underklass för icke-samtidiga Operation :

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
    }

}

Lägg till en operation i en OperationQueue :

1,0
myQueue.addOperation(operation)

Detta kommer att utföra operationen samtidigt i kön.

Hantera beroenden av en Operation .

Beroenden definierar andra Operation som måste köras i en kö innan den Operation anses redo att genomföras.

1,0
operation2.addDependency(operation1)

operation2.removeDependency(operation1)

Kör en Operation utan kö:

1,0
   operation.start()

Beroende kommer att ignoreras. Om detta är en samtidig operation, kan uppgiften fortfarande utföras samtidigt om dess start metod avlastar arbeta för att bakgrunds köer.

Samtidig verksamhet.

Om uppgiften som en Operation ska utföra är själva asynkron (t.ex. en URLSession ), bör du implementera Operation som en samtidig operation. I det här fallet din isAsynchronous bör genomförandet returnera true , skulle du i allmänhet start metod som utför en viss installation, anropar sedan dess main metod som faktiskt utför uppgiften.

När implementeringen av en asynkron Operation börjar måste du implementera isExecuting , isFinished metoder och KVO. Så när exekveringen startar, isExecuting egendom till true . När en Operation slutför sin uppgift är isExecuting inställt på false och isFinished är satt till true . Om operationen avbryts är både isCancelled och isFinished ändras till true . Alla dessa egenskaper kan observeras nyckelvärde.

Avbryt en Operation .

cancel ändrar helt isCancelled egenskapen isCancelled till true . För att svara på avbokning från din egen Operation underklass, bör du kontrollera värdet på isCancelled åtminstone regelbundet inom main och svara på lämpligt sätt.

1,0
operation.cancel()


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow