Reputation: 1213
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
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