I followed the reworked version of the fetchCoursesUsingCompletionHandler method for Swift 2. I thought it had a “pyramid of doom” ripe for the guard capability. The problem is that guard (AFAIK) unconditionally finishes the function, but the completion handler has an unconditional call to the main queue. Since the guard-able code is all about generating a result value, I can encapsulate it into an inner function:
func fetchCoursesUsingCompletionHandler(completionHandler: FetchCoursesResult -> Void) {
let url = NSURL(string: "https://bookapi.bignerdranch.com/courses.json")!
let request = NSURLRequest(URL: url)
let task = session.dataTaskWithRequest(request, completionHandler: { data, response, error in
func findResultFrom(data: NSData?, response: NSURLResponse?, error: NSError?) -> FetchCoursesResult {
guard let data = data else {
guard let error = error else {
let error = self.errorWithCode(-1, localizedDescription: "Unexplained error")
return .Failure(error)
}
return .Failure(error)
}
guard let response = response as? NSHTTPURLResponse else {
let error = self.errorWithCode(1, localizedDescription: "Unexpected response object.")
return .Failure(error)
}
print("\(data.length) bytes, HTTP \(response.statusCode).")
if response.statusCode == 200 {
return FetchCoursesResult { try self.coursesFromData(data) }
} else {
let error = self.errorWithCode(2, localizedDescription: "Bad status code \(response.statusCode)")
return .Failure(error)
}
}
let result = findResultFrom(data, response: response, error: error)
NSOperationQueue.mainQueue().addOperationWithBlock({
completionHandler(result)
})
})
task.resume()
}
Now I can use the guard technique all I want in the inner function. Note that there is an inner guard. That’s because the top level error was originally unconditionally used with a “!”. The new code checks if error is valid before using it; necessitating a new error code if an error is needed but not provided!