1. Dispatch Groups
- With Dispatch Groups, you can group together multiple tasks
- You can either wait for them to complete or receive a notification once they finish
- Tasks can be asynchronous or synchronous and can even run on different queues.
2. Using dispatch groups with synchronous wait()
method
// 1
DispatchQueue.global(qos: .userInitiated).async {
var storedError: NSError?
// 2
let dispatchGroup = DispatchGroup()
for address in [
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
] {
guard let url = URL(string: address) else { return }
// 3
dispatchGroup.enter()
let photo = DownloadRemoteImage(url: url) { _, error in
storedError = error
// 4
dispatchGroup.leave()
}
}
// 5
dispatchGroup.wait()
// 6
DispatchQueue.main.async {
completion?(storedError)
}
}
-
The synchronous
wait
method blocks the current thread. Thus, you need to useDispatchQueue.main.async
to place the entire method into a background queue. This ensures you don’t block themain thread
. -
Create a new dispatch group.
- Call
enter()
to manually notify the group that a task has started. You must balance out the number ofenter()
calls with the number ofleave()
calls, or your app will crash. - Notify the group that this work is done.
- Call
wait()
to block the current thread while waiting for tasks’ completion. This waits forever — which is fine because the photos creation task always completes. You can usewait(timeout:)
to specify a timeout and bail out on waiting after a specified time. - At this point, you know that all image tasks have either completed or timed out. You then make a call back to the main queue to run your completion closure.
3. Using dispatch groups with asynchronous method (notify(queue:work:))
var storedError: NSError?
// 2
let dispatchGroup = DispatchGroup()
for address in [
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
"https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
] {
guard let url = URL(string: address) else { return }
dispatchGroup.enter()
let photo = DownloadRemoteImage(url: url) { _, error in
storedError = error
dispatchGroup.leave()
}
}
// 2
downloadGroup.notify(queue: DispatchQueue.main) {
completion?(storedError)
}
- You don’t need to put the method in an async call since you’re not blocking the main thread.
notify(queue:work:)
serves as the asynchronous completion closure. It runs when there are no more items left in the group.
Comments !