サーチ…


前書き

関連トピック:

グランドセントラルディスパッチ

並行性

前書き

複数のスレッドが実行されているとします。各スレッドは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内に出口を持っていなければなりません。あなたがenteringleaveentering leaveことを忘れた場合、あなたは自分自身を設定しています。タスクが完了したら、決して通知されません。

enterの額は、 leaveの額に等しい必要があります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow