2

My iOS app is getting JSON response from server

let myURL = NSURL(string: SERVER_URL);
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = ""
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
    {
        data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        dispatch_async(dispatch_get_main_queue(),{

            var json = JSON(data: data!)
            let someInt = json["someInt"].int
            let message = json["message"].stringValue

Sometimes server is down or there may be errors in JSON so there will be no such values (message, someInt) and I want to handle it without app crash - what can I do?

moonvader
  • 19,761
  • 18
  • 67
  • 116

4 Answers4

3

With SwiftyJSON, non-optional getters end with Value, and optional getters don't.

So to test if the value is here you can use optional binding with if let:

if let someInt = json["someInt"].int,
    message = json["message"].string {
        // someInt and message are available here
} else {
    // someInt and message are not available
}

Or with guard:

guard let someInt = json["someInt"].int,
    message = json["message"].string else {
        // error, someInt and message are not available
        return
}
// someInt and message are available here
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • Not SwiftyJSON but a good example of how to handle errors: http://stackoverflow.com/a/31808605/2227743 – Eric Aya Jul 07 '16 at 11:01
2

Very simple, probably you already know it, you could protect your code with:

if  let someInt = json["someInt"].int {
    // do whatever you want with someInt
}
if let message = json["message"].string {
    // do whatever you want with message
}

Try this approach:

request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
                data, response, error in
                if let data = data,
                   jsonString = NSString(data: data, encoding: NSUTF8StringEncoding)
                    where error == nil {
                        var json = JSON(data: data!)
                        // use some protection as explained before..
                } else {
                    print("error=\(error!.localizedDescription)")
                }
            }
task.resume()
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
  • I think the problem is somewhere before ( `var json = JSON(data: data!)` ) too – Luca D'Alberti Jul 07 '16 at 10:35
  • `NSString(data:_, encoding:_)` accepts non-optional values, yo should validate the `data` before (since NSURLSession returns an optional data). Then you cannot assume that responseString is not null. This could cause crashes – Luca D'Alberti Jul 07 '16 at 10:46
1

Let me post my answer too =)

first of all you can implement small extension for failure JSON initializer:

extension JSON {
    init?(_ data: NSData?) {
        if let data = data {
            self.init(data: data)
        } else {
            return nil
        }
    }
}

You may put it in global scope with SwiftyJSON imported and forget about forcing unwrap your data before use it in JSON. Same fail initializers can be written for other data types if you use them. Its only for a bit shorter and readable code in future. With many routes or in some cases, for example when you wait from json some single fields, this extension can make your code looks extremely easy and readable:

guard let singleMessage = JSON(data: data)?["message"].string else {return}

Then you need to check for nil in way that you need (in fact explained in previous answers). Probably you searching for fully valid data, so use if-let chain:

let myURL = NSURL(string: SERVER_URL);
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = ""
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
    {
        data, response, error in

        if error != nil {
            print("error=\(error)")
            return
        }

        dispatch_async(dispatch_get_main_queue()) {

            if let json = JSON(data: data),
                   someInt = json["someInt"].int,
                   message = json["message"].string,
                   // ...
            {
                // all data here, do what you want

            } else {
                print("error=\(error)")
                return
            }
        }
    }
Yury
  • 6,044
  • 3
  • 19
  • 41
0

The best would be to handle using try catch

request.HTTPBody = postdata.dataUsingEncoding(NSUTF8StringEncoding)
    let task  = NSURLSession.sharedSession().dataTaskWithRequest(request)
    {
        (data, response, error) in
        dispatch_async(dispatch_get_main_queue(), {
        var jsondata: AnyObject?
        do
        {
            let jsondata = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
            print(jsondata)
            // your code here
        }
        catch
        {
                print("Some Error Found")
        }
    })

    }

    task.resume()

If you encounter any error, you will receive a message in the console, thus preventing the application from crashing

ADK
  • 139
  • 10