I would like to create a function in Swift 2 that gets data from a URL and returns it as a JSON object using NSURLSession. At first, this seemed pretty straight forward. I wrote the following:
func getJson(url:NSURL, completeWith: (AnyObject?,NSURLResponse?,NSError?)->Void) -> NSURLSessionTask? {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {
(data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if error != nil {
completeWith(nil, response, error)
}
if let data = data {
do {
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as NSError {
completeWith(nil, response, caught)
}
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
}
return task
}
However, that doesn't compile because the completion block doesn't declare "throws". The exact error is Cannot invoke 'dataTaskWithURL' with an argument list of type '(NSURL, (NSData?, NSURLResponse?, NSError?) throws -> Void)'
. Even though I'm catching all errors in my do/catch
statement, Swift still wants to propagate the NSError up the chain. The only way I can see around it is to use try!
, like this:
if let data = data {
let object:AnyObject? = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
Now everything compiles just fine, but I've lost the NSError that's thrown by NSJSONSerialization.JSONObjectWithData
.
Is there was I can capture the NSError potentially thrown by NSJSONSerialization.JSONObjectWithData
and propagate it to the completion block without modifying the completion block's signature?
I think, your catch is not exhaustive, so you need something like this: