1. Use dispatch_group_create() to create a group.
2. Call dispatch_group_enter(group) before starting each download task.
3. Call dispatch_group_leave(group) inside the task's completion handler.
4. Then call dispatch_group_notify(group, queue, ^{ ... }) to enqueue a block that will be executed when all the tasks are completed.
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
// do something, including background threads
dispatchGroup.leave()
dispatchGroup.notify(queue: DispatchQueue.main) {
// completion code
}