DispatchGroup 介紹
假設你有多個執行緒正在執行。每個執行緒都在執行一項任務。當所有任務執行緒都完成時,你希望在 mainThread 或其他執行緒上收到通知。
這個問題的最簡單的解決方案是 DispatchGroup
。
當使用 DispatchGroup
時,對於每個請求,你都可以分組,並且對於每個完成的請求,你都可以使用 DispatchGroup
。
當群組中不再有請求時,你將成為 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
中有一個出口。如果你在 entering
之後忘記了 leave
,那麼你就是在為自己做好準備。任務完成後,你將永遠不會收到通知。
enter
的數量必須等於 leave
的數量。