Leave a rating/review
Use Group of Tasks
Open UseGroupOfTasks.playground in the starter folder. In Sources, there’s a SlowSum file with a slowAdd(_:) function. You’ll create a group of slowAdd tasks and run them on userQueue:
let userQueue = DispatchQueue.global(qos: .userInitiated)
Here’s an array of number pairs that you’ll slowAdd:
let numberArray = [(0,1), (2,3), (4,5), (6,7), (8,9)]
First, create a dispatch group with the default initializer:
let slowAddGroup = DispatchGroup()
Now, loop over numberArray, specifying this dispatch group as an argument when you call userQueue’s async method to dispatch a task:
for inValue in numberArray {
userQueue.async(group: slowAddGroup) { // pause to point out group: method
let result = slowAdd(inValue)
print("Result = \(result)")
}
}
Each task slowAdds a pair of Ints, then prints the result. Next, define a handler for when every task in the dispatch group finishes, specifying the queue where the handler will run:
slowAddGroup.notify(queue: mainQueue) { // indicate queue:work: method
print("SLOW ADD: Completed all tasks")
sleep(3)
PlaygroundPage.current.finishExecution()
}
You also call finishExecution here, to stop the playground when the tasks finish. Run the playground and open the debug area to see the output:
=== Group of sync tasks ===
Result = 9
Result = 17
Result = 13
Result = 1
Result = 5
SLOW ADD: Completed all tasks
The notify handler runs after all the tasks finish. Your tasks might complete in a different order.
Close this playground and open DispatchGroupWaiting.playground.
DispatchGroup Waiting
If the current queue really can’t do anything until the group finishes, you can call wait. Unlike waiting for a dispatch work item, which promotes the priority of the queue you dispatched the work item to, the dispatch system doesn’t promote any of the queues used by group tasks. The only reason I can think of to wait for a group is to free up the current thread, so the group tasks can use it.
This playground has a dispatch group, a dispatch queue, and two very similar tasks:
let group = DispatchGroup()
let queue = DispatchQueue.global(qos: .userInitiated)
queue.async(group: group) {
print("Start task 1")
print("End task 1")
}
queue.async(group: group) {
print("Start task 2")
print("End task 2")
}
Add code to make the tasks sleep for different times. Task 1 sleeps for 4 seconds:
sleep(4) // between print statements
And task 2 sleeps for 1 second:
sleep(1) // between print statements
Now write the notify handler to print a message and stop the playground:
print("All tasks completed at last!")
sleep(1)
PlaygroundPage.current.finishExecution()
The 1-second sleep gives the print message time to appear. Run the playground:
Start task 1
Start task 2
End task 2
End task 1
All tasks completed at last!
No surprises: Task 1 ends after task 2 because it sleeps 3 seconds longer. Now, make the current thread wait long enough for task 1 to finish:
if group.wait(timeout: .now() + 5) == .timedOut {
print("I got tired of waiting.")
} else {
print("All the tasks have completed.")
}
You wouldn’t do this on the main queue in an app, but it’s OK to do it in a playground. The if condition becomes true after 5 seconds. If the group tasks complete before the wait times out, the else closure executes.
Run the playground:
Start task 1
Start task 2
End task 2
End task 1
All tasks completed at last!
All the tasks have completed.
Now reduce the wait time to 3 seconds and run the playground:
Start task 1
Start task 2
End task 2
I got tired of waiting.
End task 1
All tasks completed at last!
This time, the wait times out before task 1 finishes, but task 1 continues to run then finish, triggering the dispatch group’s notify handler. Now you know how to use dispatch groups. Next, you’ll wrap an asynchronous function so you can add it to a dispatch group.