iOS
DispatchGroup
サーチ…
前書き
前書き
複数のスレッドが実行されているとします。各スレッドは1つのタスクを実行しています。すべてのタスクスレッドが完了したときに、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
内に出口を持っていなければなりません。あなたがentering
しleave
後entering
leave
ことを忘れた場合、あなたは自分自身を設定しています。タスクが完了したら、決して通知されません。
enter
の額は、 leave
の額に等しい必要があります。
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow