iOS
DispatchGroup
Поиск…
Вступление
Вступление
Предположим, что у вас несколько потоков. Каждый поток выполняет одну задачу. Вы хотите получать уведомления либо на mainThread ИЛИ в другом потоке, когда все задачи-потоки завершены.
Простейшим решением такой проблемы является DispatchGroup
.
При использовании группы DispatchGroup
для каждого запроса вы enter
группу, и для каждого завершенного запроса вы leave
группу.
Если в группе больше нет запросов, вы будете notify
(уведомлены).
Использование:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let dispatchGroup = DispatchGroup() //Create a group for the tasks.
let session: URLSession = URLSession.shared
dispatchGroup.enter() //Enter the group for the first task.
let firstTask = session.dataTask(with: URLRequest(url: URL(string: "https://stackoverflow.com")!)) { (data, response, error) in
//Process Response..
dispatchGroup.leave() //Leave the group for the first task.
}
dispatchGroup.enter() //Enter the group for the second task.
let secondTask = session.dataTask(with: URLRequest(url: URL(string: "https://google.ca")!)) { (data, response, error) in
//Process Response..
dispatchGroup.leave() //Leave the group for the second task.
}
//Get notified on the main thread/queue.. when ALL of the tasks above has been completed.
dispatchGroup.notify(queue: DispatchQueue.main) {
print("Every task is complete")
}
//Start the tasks.
firstTask.resume()
secondTask.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
С вышесказанным вам не нужно wait
бесконечно, пока все задачи не будут завершены. Вы можете отобразить загрузчик перед началом всех задач и отпустить загрузчик ПОСЛЕ завершения всех задач. Таким образом, ваш основной поток не блокируется, и ваш код остается чистым.
Предположим, вы также хотели, чтобы задания ordered
или добавляли свои ответы в массив последовательно. Вы можете сделать следующее:
import UIKit
//Locking mechanism..
func synchronized(_ lock: AnyObject, closure: () -> Void) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
class ViewController: UIViewController {
let lock = NSObject() //Object to lock on.
var responseArray = Array<Data?>() //Array of responses.
override func viewDidLoad() {
super.viewDidLoad()
let dispatchGroup = DispatchGroup()
let session: URLSession = URLSession.shared
dispatchGroup.enter() //Enter the group for the first task.
let firstTask = session.dataTask(with: URLRequest(url: URL(string: "https://stackoverflow.com")!)) { (data, response, error) in
//Process Response..
synchronized(self.lock, closure: { () -> Void in
self.responseArray[0] = data ?? nil
})
dispatchGroup.leave() //Leave the group for the first task.
}
dispatchGroup.enter() //Enter the group for the second task.
let secondTask = session.dataTask(with: URLRequest(url: URL(string: "https://google.ca")!)) { (data, response, error) in
//Process Response..
synchronized(self.lock, closure: { () -> Void in
self.responseArray[1] = data ?? nil
})
dispatchGroup.leave() //Leave the group for the second task.
}
//Get notified on the main thread.. when ALL of the requests above has been completed.
dispatchGroup.notify(queue: DispatchQueue.main) {
print("Every task is complete..")
for i in 0..<self.responseArray.count {
if self.responseArray[i] == nil {
print("Request #\(i) Failed.\n")
}
else {
print("Request #\(i) Succeeded.\n")
}
}
}
//Two tasks added to the array. Responses are assumed nil until they complete.
self.responseArray.append(nil)
self.responseArray.append(nil)
//Start the tasks.
firstTask.resume()
secondTask.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Заметки
Каждая запись должна иметь выход в DispatchGroup
. Если вы забыли leave
после entering
, вы настраиваете себя. Вы никогда не будете уведомлены, когда задачи будут завершены.
Сумма enter
должна быть равна размеру leave
.