iOS
DispatchGroup
Recherche…
Introduction
introduction
Supposons que vous ayez plusieurs threads en cours d'exécution. Chaque thread effectue une tâche. Vous voulez être notifié soit sur le thread principal ou un autre thread, lorsque tous les threads de tâches sont terminés.
La solution la plus simple à un tel problème est un DispatchGroup
.
Lorsque vous utilisez un DispatchGroup
, pour chaque demande, vous enter
le groupe et pour chaque demande terminée, vous leave
le groupe.
Quand il n'y a pas de demandes plus dans le groupe, vous serez en notify
(notification).
Usage:
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()
}
}
Avec ce qui précède, vous n'avez pas à wait
indéfiniment jusqu'à ce que toutes les tâches soient terminées. Vous pouvez afficher un chargeur AVANT que toutes les tâches aient démarré et fermer le chargeur APRÈS que toutes les tâches soient terminées. De cette façon, votre thread principal n'est pas bloqué et votre code reste propre.
Supposons maintenant que vous souhaitiez également ordered
les tâches ou ajouter leurs réponses à un tableau de manière séquentielle. Vous pouvez faire ce qui suit:
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()
}
}
Remarques
Chaque entrée doit avoir une sortie dans un DispatchGroup
. Si vous oubliez de leave
après être entering
, vous vous mettez en place. Vous ne serez JAMAIS averti lorsque les tâches sont terminées.
Le montant de l' enter
doit être égal au montant du leave
.