Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run synchronically two functions with async operations on iOS using Swift

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!.

like image 392
mike83_dev Avatar asked Nov 27 '14 18:11

mike83_dev


3 Answers

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)
}
like image 169
ylin0x81 Avatar answered Nov 03 '22 03:11

ylin0x81


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)
}
like image 44
JaseTheAce Avatar answered Nov 03 '22 02:11

JaseTheAce


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
    }
}
like image 26
Daniel T. Avatar answered Nov 03 '22 03:11

Daniel T.