Recherche…


Introduction

Rubriques connexes:

Expédition Grand Central

Concurrence

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 .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow