Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift 2, how can I return JSON parsing errors to the completion block?

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?

like image 780
Andy S Avatar asked Jun 15 '15 04:06

Andy S


People also ask

How do I get an Alamofire response in Swift?

Follow the steps given in the previous chapter to install Alamofire in the application and open the xcworkspace file. Create a MainViewController class and make a get request to print the API data using Alamofire. // Do any additional setup after loading the view. print("Response.

What is Jsonserialization in Swift?

An object that converts between JSON and the equivalent Foundation objects.

What is JSON parsing in Swift?

Swift JSON Parsing JSON stands for JavaScript Object Notation. It's a popular text-based data format used everywhere for representing structured data. Almost every programming language supports it with Swift being no exception. You are going to use JSON a lot throughout your career, so make sure you don't miss out.


2 Answers

I think, your catch is not exhaustive, so you need something like this:

do
{
  let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
  completeWith(object, response, nil)
} catch let caught as NSError {
  completeWith(nil, response, caught)
} catch {
  // Something else happened.
  // Insert your domain, code, etc. when constructing the error.
  let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil)
  completeWith(nil, nil, error)
}
like image 99
Sergey A. Novitsky Avatar answered Nov 03 '22 11:11

Sergey A. Novitsky


to address the question from Jguffey. I saw the same error when I tried calling the function like this:

let taskResult = getJson(url!) { 
     (any: AnyObject,resp: NSURLResponse,error: NSError) in

it should be like this:

let taskResult = getJson(url!) { 
         (any: AnyObject?,resp: NSURLResponse?,error: NSError?) in
like image 30
beachCode Avatar answered Nov 03 '22 10:11

beachCode