2

I'm trying to learn Swift and am struggling with understanding a piece about handling JSON and get "fatal error: unexpectedly found nil while unwrapping an Optional value" from using this code:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var webView: UIWebView!

override func viewDidLoad() {
    super.viewDidLoad()

    let urlPath = "http://api.worldweatheronline.com/free/v2/marine.ashx?key=45e8e583134b4371a2fa57a9e5776&format=xml&q=45,-2"
    let url: NSURL = NSURL(string: urlPath)!
    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
        println("Task completed")
        if ((error) != nil) {
            println(error)

        } else {
            var err: NSError?
            println("URL: \(url)")

            var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

            println(jsonResult)
        }


    })

    task.resume()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

The API key I'm using is free so don't worry about using it. The JSON results should look something like this but I am instead greeted with:

Task completed    
URL: http://api.worldweatheronline.com/free/v2/marine.ashx?key=45e8e583134b4371a2fa57a9e5776&format=xml&q=45,-2
fatal error: unexpectedly found nil while unwrapping an Optional value

I'm assuming the jsonResult variable is what's causing the problem, but even if I try to force unwrap it (I think that's what I'm doing?) with something like

var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary

it still fails with "expected type after 'as'."

1
  • 1
    http://api.worldweatheronline.com/free/v2/marine.ashx?key=45e8e583134b4371a2fa57a9e5776&format=xml&q=45,-2 returns XML, not JSON. Commented Mar 3, 2015 at 0:39

2 Answers 2

1

Everything is fail-able here, a website can even return 200 but return nothing, the data can come corrupted, and, in your case, I tried calling the URL you are using and found out, it's actually XML, so... there's your problem?

A more robust approach (assuming that you still want to parse JSON, maybe from another site? The ISS has an open API) is to use the if let to unwrap optionals and then on the else case deal with the errors, rather than ! your way to success.

Here's a very extensive check of everything

task = session.dataTaskWithRequest(NSURLRequest(URL: url), completionHandler: { [unowned self] (data, response :NSURLResponse!, errorRequest) -> Void in
    // Check the HTTP Header
    if let responseHTTP = response as? NSHTTPURLResponse
    {
        if responseHTTP.statusCode != 200
        {
            println("Received status code \(responseHTTP.statusCode)")
            return
        }
    }
    else
    {
        println("Non-HTTP Response received")
        return
    }

    var errorParsing : NSError?

    if let JSON = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &errorParsing) as? NSDictionary
    {
        // Do the parsing
    }
    else
    {
        println("Error parsing: \(errorParsing)")
    }
})

task!.resume()
Sign up to request clarification or add additional context in comments.

1 Comment

Holy cow. Yeah, the problem is definitely related to the fact that I was trying to parse XML as JSON. api.worldweatheronline.com/free/v2/… works!
1

NSJSONSerialization.JSONObjectWithData... returns an optional NSData?. This means that you can't cast it directly to NSDictionary. To fix the crash you will need to use ?as which means your jsonResult will either be a NSDictionary or nil

var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) ?as NSDictionary

In your case, you can safely unwrap the optional by doing this.

var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)

if let jsonResult = jsonResult ?as NSDictionary {
println(jsonResult)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.