user6820041
user6820041

Reputation: 1213

Chaining closures and completion handlers Swift 3

I'm having a hard time understanding how chaining completion handlers with closures works.

The example I'm working with is the following :

typealias CompletionHandler = (_ result: AnyObject?, _ error: NSError?) -> Void
func getRequestToken(completionHandler: CompletionHandler){
    taskForGET(path: "PathToWebsite.com") { (result, error) in
        if let error = error {
            print(error)
        } else {
            print(result)
        }
    }
}

func taskForGET(path: String, completionHandler: CompletionHandler) {
    //URLSESSIONCODE with completion handler
    (data, response, error) {
        if let error = error {
            CompletionHandler(result: nil, error: error)
        } else {
            let data = data
            parseJSON(data: data, completionHandler: completionHandler)
        }
    }

}
func parseJSON(data: NSData, completionHandler: CompletionHandler) {
    //SerializingJSON with do catch block
    do {
        completionHandler(result: theResult, error: nil)
    } catch {
        completionHandler(result: nil, error: error)
    }
}

So basically what this code does is it kicks off a GET request to a server. If the GET request sends back data, then it parses it into JSON. If at any point along the way something fails, it returns an error.

I understand basically what is going on here, but I don't understand how the completion handlers are being fired off.

First taskForGET is called which has a completion handler as a parameter that can return a result or an error, I've got that.

The next step is calling parseJSON, where the data from taskForGET is passed but then the completionhandler that's being passed is taskForGET's completion handler. I don't understand this at all.

Then down in parseJSON, the completion handler either returns JSON or an error by calling the completion handler from its parameters..which in this case is taskForGET's completion handler?

I don't understand the flow. Even once we've parsed JSON successfully, how does calling taskForGET's result ever get back up to getRequestToken.

Any help with this would be appreciated.

Upvotes: 2

Views: 1303

Answers (1)

vadian
vadian

Reputation: 285039

There is only one completion handler which is passed from one method to another.

Lets declare the handler separately, btw. in Swift 3 omit the parameter labels in the type alias:

typealias CompletionHandler = (Any?, Error?) -> Void

let handler : CompletionHandler = { (result, error) in
    if let error = error {
        print(error)
    } else {
        print(result)
    }
}

This closure is supposed to be executed at the end of the process. Now the getRequestToken method looks like

func getRequestToken(completionHandler: CompletionHandler){
    taskForGET(path: "PathToWebsite.com", completionHandler: handler)
}

The handler / closure is passed as a parameter from getRequestToken to taskForGET and then from taskForGET to parseJSON but it's always the same object.

Upvotes: 3

Related Questions