Fabian Boulegue
Fabian Boulegue

Reputation: 6608

Parse JSON in SWIFT

Hi i try to find a way to parse JSON in SWIFT, this works great for me but i run into a problem.

I let the user enter a username that is used for the JSON URL -> if the user type in a valid username all works fine.

But if he enter a wrong username my parsing fails, this is correct too, but for now my app only crashes and i looking for a way to make a work around.

This is my Code where it crashes,

 let url0 = NSURL(string: newUrlPath!)
        let session0 = NSURLSession.sharedSession()
        let task0 = session0.dataTaskWithURL(url0!, completionHandler: {data, response, error -> Void in
            if (error != nil) {
                println(error)
            } else {
                let summonorID_JSON = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

The Xcode Error

Error Domain=NSURLErrorDomain Code=-1002 "The operation couldn’t be completed. (NSURLErrorDomain error -1002.)" UserInfo=0x7c12d610 {NSErrorFailingURLKey=XX, NSErrorFailingURLStringKey=XX, NSUnderlyingError=0x7c12c8d0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1002.)"} fatal error: unexpectedly found nil while unwrapping an Optional value

All is fine cause this is the return page i get from my Request

https://br.api.pvp.net/api/lol/br/v1.4/summoner/by-name/smirknaitiax?api_key=5c7d4d4f-f320-43d5-8647-643c9f6ee5de

And yes he can't parse this into a NSDirectory as its no JSON that returns (as its normally is) is there a way to take care that if this page comes up (so the user entered a wrong username) that i can exit my loop/take a other way ;)?

Upvotes: 0

Views: 1624

Answers (4)

TheLittleHawk
TheLittleHawk

Reputation: 628

Since you are getting 404 on this request, I assume that this will happen every time something is bad with username, you should handle server response to fit that. First thing will be to check what server returned:

let httpResp: NSHTTPURLResponse = response as NSHTTPURLRespons

At this point you can access statusCode property, that will tell you if request was good or not (404). Having that information you can decide what to do, and for example, you can modify your code something like this:

let url0 = NSURL(string: newUrlPath!)
let session0 = NSURLSession.sharedSession()
let task0 = session0.dataTaskWithURL(url0!, completionHandler: {data, response, error -> Void in
    if (error != nil) {
        println(error)
    } else {
        let httpResp: NSHTTPURLResponse = response as NSHTTPURLRespons
        httpResp.statusCode != 404 {
            let summonorID_JSON = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        } else {
            // Handle error at this point, tell user to retype username etc.
        }
    })

Upvotes: 2

gnasher729
gnasher729

Reputation: 52530

You are using many operations which could all fail, and Swift is quite unforgiving about failure. Your code will crash if newURLPath is nil, if url0 is nil because newURLPath wasn't a valid URL.

So your URL request might return an error (the request itself failed), but you have the case that the URL request succeeded but gives unexpected results (not a JSON dictionary). Your code ending in "as NSDictionary" tells Swift: "I know I might not get a dictionary, but convert what you get to a dictionary and crash if this doesn't work". Just change this to

if let parsedJSON = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
{
    // Will still crash if the server sends a valid JSON array
    let summonorID_JSON = parsedJSON as NSDictionary
}
else
{
    // data wasn't valid JSON, handle it. 
}

The difference is that the optional value returned by the JSON parser will be accepted without crashing, and you check whether you received valid JSON or not.

Upvotes: 3

Vignesh
Vignesh

Reputation: 10251

The url0 becomes nil if user enter wrong data. If you use the nil value as url0! app will crash.

When you add a ! after a variable you tell the compiler the value will not be nil.

so to avoid the crash, you have to check for nil condition before calling

  let task0 = session0.dataTaskWithURL(url0!, completionHandler: {data, response, error -> Void in

Upvotes: -1

zisoft
zisoft

Reputation: 23078

NSURL is a failable initializer and exactly this happens when you give an invalid url: It fails to initialize.

So wrap your code in an conditional unwrap:

if let url0 = NSURL(string: newUrlPath!) {
    ...
}

Upvotes: 0

Related Questions