Search code examples
iosswiftalamofiregrand-central-dispatchnsurlrequest

Wait until multiple request to be executed and their completion block


Consider a scenario, I have a function "REFRESH", this function is called by different methods simultaneously, let's say the methods are "A", "B", "C". If method "A" calls "REFRESH TOKEN" firstly then methods "B" and "C" should wait until it finishes.

How can I attain this scenario? Appreciate your help!

let serialQueue = DispatchQueue(label: "serialQueue")
var myFlag = false


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    self.refresh(param: 1) // Method A
    self.refresh(param: 2) // Method B
    self.refresh(param: 3) // Method C

}

// Method REFRESH

func refresh(param: NSInteger) -> Void {

let absolutePath = "MY SAMPLE API"
var headers: [String: String] = Dictionary<String, String>();
headers["Content-Type"] = "application/json"


serialQueue.sync {
    print("\nEntered ", param)
Alamofire.request(absolutePath, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseString {
    response in
    switch response.result {
    case .success:
        print("SUCCESS")
        break
    case .failure(let error):
        print(error)
    }

}

Above code output:

Entered  1
Entered  2
Entered  3
SUCCESS
SUCCESS
SUCCESS

I need an output like this:

Entered  1
SUCCESS
Entered  2
SUCCESS
Entered  3
SUCCESS

Solution

  • What you need is something called resource locking. You can achieve this by using DispatchGroup.

    First you need to create a DispatchGroup. Add a property in your controller:

    let dispatchGroup = DispatchGroup()
    

    Then modify your refresh(param:) function as: (I've modified some of the coding patterns)

    func refresh(param: NSInteger) -> Void {
        // You lock your resource by entering to the dispatch group
        dispatchGroup.enter()
        let absolutePath = "MY SAMPLE API"
        var headers = [String: String]()
        headers["Content-Type"] = "application/json"
        print("Entered \(param)")
        Alamofire.request(absolutePath, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseString { [weak self] (response) in
            switch response.result {
            case .success:
                print("SUCCESS \(param)")
                break
            case .failure(let error):
                print(error)
            }
            // You release the resource as soon as you get the response so that other processes may be able to use the resource
            self?.dispatchGroup.leave()
        }
        // The lock continues by invoking the wait method
        dispatchGroup.wait()
    }
    

    So, this will work as:

    Method 1 & Method 2 are requesting to use the same resource. When Method 1 is executing, Method 2 will wait for Method 1 to finish. When Method 1 is finished, Method 2 will be given the opportunity to start it's execution.

    So, basically which method first starts executing will finish and then the other will be started. Though it's not guaranteed which will start the execution first (As, you don't need dependency on each other). But it will depend on the sequence you invoke this method.