9

lets propose this scenario

a method with async network operations

func asyncMethodA() -> String?
{
   result : String?
   Alamofire.manager.request(.POST, "https://www.apiweb.com/apimethod", parameters: parameters, encoding:.JSON)
            .response { (request, response, rawdata, error) in
                if (response?.statusCode == 200)
                {
                    //DO SOME HEAVY LIFTING
                }
        }
        return result //string

}

another method with async network operations

func asyncMethodB() -> String?
{
   result : String?
   Alamofire.manager.request(.POST, "https://www.yetanotherapiweb.com/apimethod", parameters: parameters, encoding:.JSON)
            .response { (request, response, rawdata, error) in
                if (response?.statusCode == 200)
                {
                    //DO SOME HEAVY LIFTING

                }
        }
        return result //string
}

a method in which i shall call those methods A and B, to do some operations

func displayResult
{
   1)  let a = asyncMethodA()
   2)  let b = asyncMethodB()
   3)  println(a + b) //some chaotic stuff might happen :(
}

so the question is how i could make that (2) waits for (1) to run, and (3) waits for (2) and so on (that 1,2 and 3 run syncronised)?

(i know that one answer is to chain asyncMethodA and displayResult into asyncMethodB, but want to know if there is some other method)

thank you!.

3
  • 2
    Are you aware that return result in your async functions is executed before the data has been retrieved from the network? Commented Nov 27, 2014 at 19:04
  • I'm not even sure where result is declared. Commented Nov 27, 2014 at 19:19
  • yep, i havent seen that too... another problem haha, one possible solution is to use a global variable and to check if has a value different from nil, but if you know an answer for this specific instance of the problem, it would be highly appreciated. Commented Nov 27, 2014 at 19:22

3 Answers 3

18
func anAsyncMethod(resultHandler: (result: AnyObject) -> Void) {
    ...        
}

func anotherAsyncMethod(resultHandler: (result: AnyObject) -> Void) {
    ... 
}

let operationQueue = NSOperationQueue()

func performWithCompletionHandler(completion: (AnyObject?, AnyObject?) -> Void) {
        var resultOfOperation1: AnyObject?
        var resultOfOperation2: AnyObject?

        let operation1 = NSBlockOperation {
                let dispatchGroup = dispatch_group_create()
                dispatch_group_enter(dispatchGroup)
                self.anAsyncMethod {
                        result in
                        resultOfOperation1 = result
                        dispatch_group_leave(dispatchGroup)
                }
                // wait until anAsyncMethod is completed
                dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER)
        }

        let operation2 = NSBlockOperation {
                let dispatchGroup = dispatch_group_create()
                dispatch_group_enter(dispatchGroup)
                self.anotherAsyncMethod {
                        result in
                        resultOfOperation2 = result
                        dispatch_group_leave(dispatchGroup)
                }
                // wait until anotherAsyncMethod is completed
                dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER)
        }

        let completionOperation = NSBlockOperation {
                // send all results to completion callback
                completion(resultOfOperation1, resultOfOperation2)
        }

        // configuring interoperation dependencies
        operation2.addDependency(operation1)
        completionOperation.addDependency(operation2)

        operationQueue.addOperations([operation1, operation2, completionOperation], waitUntilFinished: false)
}
Sign up to request clarification or add additional context in comments.

Comments

5

Thanks Yimin for the code above. I've updated it to the latest Swift syntax so just posting to be helpful:

func anAsyncMethod(resultHandler: (_ result: AnyObject) -> Void) {
    ...
}

func anotherAsyncMethod(resultHandler: (_ result: AnyObject) -> Void) {
    ...
}

func performWithCompletionHandler(completion: @escaping (AnyObject?, AnyObject?) -> Void) {

    let operationQueue = OperationQueue()

    var resultOfOperation1: AnyObject?
    var resultOfOperation2: AnyObject?

    let operation1 = BlockOperation {
        let dispatchGroup = DispatchGroup()
        dispatchGroup.enter()
        self.anAsyncMethod {
            result in
            resultOfOperation1 = result
            dispatchGroup.leave()
        }
        // wait until anAsyncMethod is completed
        dispatchGroup.wait(timeout: DispatchTime.distantFuture)
    }

    let operation2 = BlockOperation {
        let dispatchGroup = DispatchGroup()
        dispatchGroup.enter()
        self.anotherAsyncMethod {
            result in
            resultOfOperation2 = result
            dispatchGroup.leave()
        }
        // wait until anotherAsyncMethod is completed
        dispatchGroup.wait(timeout: DispatchTime.distantFuture)
    }

    let completionOperation = BlockOperation {
        // send all results to completion callback
        completion(resultOfOperation1, resultOfOperation2)
    }

    // configuring interoperation dependencies
    operation2.addDependency(operation1)
    completionOperation.addDependency(operation2)

    operationQueue.addOperations([operation1, operation2, completionOperation], waitUntilFinished: false)
}

Comments

1

With the below, you can launch both async methods at the same time and do your heavy lifting after whichever one finishes last.

var methodAFinished = false
var methodBFinished = false

func asyncMethodA() -> String?
{
    Alamofire.manager.request(.POST, "https://www.apiweb.com/apimethod", parameters: parameters, encoding:.JSON)
        .response { (request, response, rawdata, error) in
            if (response?.statusCode == 200) {
                methodAFinished = true
                doStuff()
            }
        }
    return result //string
}

The guts of asyncMethodB would be methodBFinished = true; doStuff()

func doStuff() {
    if methodAFinished && methodBFinished {
        // do crazy stuff
    }
}

3 Comments

I thought the idea was that there was something you wanted to do once both calls were complete? If you want to do something one just one call is complete, just put the thing in the response block.
thx for the answer, mm ok, thats interesting but when doStuff is being called if methodAFinished or methodBFinished are still on the run nothing will happen, i must assure that A and B are finished to do the next operations... i dont know if this might be able to accomplish using GCD or closures... im a newbie in threading :S
Right, when both calls are done, both methodAFinished and methodBFinished will be true, so the crazy stuff inside doStuff will happen.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.