5

I was trying to get some JSON data from a Flickr API but my Swift code is not working.
This is based on Jameson Quave's tutorial on making an API request with Swift

func GetFlickrData(tags: String) {

    let baseURL = "https://api.flickr.com/services/rest/?&method=flickr.photos.search"
    let apiString = "&api_key=\(apiKey)"
    let searchString = "&tags=\(tags)"

    let requestURL = NSURL(string: baseURL + apiString + searchString)   
    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithURL(requestURL, completionHandler: { data, response, error -> Void in

        var result = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as NSDictionary

        dispatch_async(dispatch_get_main_queue(), {
            println(result)
        })
    })

    task.resume()
}

This shows me an error for the requestURL argument that says: "Vaue of type NSURL? not unwrapped". When I add "!", the error goes away. But, I still get a runtime error when making the call.

In the debugger, I see:

data = (NSData!)16642 bytes
fatal error: unexpectedly found nil while unwrapping an Optional value

What am I missing?

EDIT - This was working fine on Xcode 6, it broke when updating Xcode to version 6.1

nv.snow
  • 864
  • 1
  • 14
  • 24

1 Answers1

6

The result variable actually is of type NSDictionary? and will raise a runtime error if it is nil and you try to access it. The JSONObjectWithData function returns an optional as you can see in it's declaration:

class func JSONObjectWithData(data: NSData, options opt: NSJSONReadingOptions, error: NSErrorPointer) -> AnyObject?

You have to cast the result in an object of type NSDictionary? and not NSDictionary in order to make it work

let result = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as NSDictionary?
if let unwrappedResult = result {
    println(unwrappedResult)
}

UPDATE FOR SWIFT 2:

JSONObjectWithData no longer returns an Optional but instead makes use of the new error handling and is marked as throwing. The signature now looks like this:

public class func JSONObjectWithData(data: NSData, options opt: NSJSONReadingOptions) throws -> AnyObject

To achieve the same one would now have to wrap the call inside a do/catch block or alternatively use try? instead of try:

do {
    let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary
    print(result)
} catch {
    print(error)
}
Daehn
  • 547
  • 6
  • 12
  • Ok, that fixed the runtime error. However, unwrappedResult is printing a nil. When I use the same URL in a browser, it gives me the JSON data I need.....but it looks like the JSONObjectWithData method is returning a nil. Any suggestions? – nv.snow Oct 25 '14 at 06:57
  • 2
    You have to tell the API in wich format you would like the response to be. This can be done by sending a "format" parameter with a value of "json". I had some problems because even then the API responds with JSONP, but I found a solution here [http://stackoverflow.com/questions/15930932/how-do-i-parse-this-flickr-response](http://stackoverflow.com/questions/15930932/how-do-i-parse-this-flickr-response). – Daehn Oct 25 '14 at 19:22
  • &nojsoncallback=1 is clutch! – Andrew Paul Simmons May 04 '19 at 21:30