Swift iOS NSJsonSerialization fails silently - ios

I have the following code fetching json data via an API.
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
// print("Response: \(response)")
// print("DATA: \(data)")
if data != nil {
do {
print( NSString(data: data!, encoding: NSUTF8StringEncoding))
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray {
print("\n\nThe return JSON looks like this: \(jsonResults)\n\n")
}
} catch {
print("\n\nProblem getting JSON back from GET API.\n\n")
}
} else {
print("API Not Available") // data was nil
}
}) // task
task.resume()
The "print" of the NSString shows what to my eyes looks like valid JSON. The console shows this as:
Optional({"id":15,"user_id":11,"breed_id":593,"gender":"Male","age_years":5,"tally":{"count":1246,"struvite":716,"calcium_oxalate":388,"urate":217,"calcium_phosphate":30,"silica":21,"compound":41},"created_at":"2016-02-04T08:26:14.719-06:00","updated_at":"2016-02-04T08:26:14.719-06:00"})
However, the "if let jsonResults =" statement does execute successfully (there is no jsonResults printed) and the catch does not execute either -- so it seems like a silent error.
A very similar call works on another part of the API. The only big difference is that "tally" in the JSON return on this call is nested.
Any suggestions are appreciated.

The JSON may not be serialised properly, so try to replace:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
with:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [String: AnyObject]

let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSMutableDictionary
This implementation is a lot neater, and you don't have to specify their data types.

The answer was a combination of dzk and ishaq's responses.
I replaced
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
with:
if let jsonResults = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
The essential piece was casting it as a Dictionary, not an Array.

Related

Swift - Forming an array from a JSON Response

I am new to the world of JSON. I just got started with JSON in Swift.
Right now, I have the following function:
func forShow() {
// Using ACORN API to fetch the course codes
guard let url[enter image description here][1]Online = URL(string: "https://timetable.iit.artsci.utoronto.ca/api/20179/courses?code=CSC") else { return }
let session = URLSession.shared
session.dataTask(with: urlOnline) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
} catch {
print(error)
}
}
}.resume()
}
I get a response with all courses having 'CSC' in their code String. I want to form an array with all complete course codes based on the response. I will paste response for one course here:
So, I want to access all the course codes seen in the image. It's "CSC104H1-F-20179" I want to to be able to access.
Treat your JSON like a dictionary. You have all the course names at the top level, so fortunately you don't have to dig deep in the hierarchy.
So, where you have:
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
print(json)
Change to:
if let arrayOfCourses = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: Any]] {
for (course, _) in arrayOfCourses {
print(course)
}
}

Could not cast value of type '__NSCFString' (0x104a67320) to 'NSDictionary' (0x104a68108)

I am trying to parsing JSON from response. But I got this error
My code is.
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
if error != nil {
print("error = \(error)")
return
}
do {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! NSDictionary
let str = json["ResultMsg"] as! NSString
print ("ResultMsg = " + (str as String))
}catch let error as NSError {
print("Error : " + error.localizedDescription)
}
}).resume()
and console log is:
responseString = Optional("{\"ResuleCode\":\"1\",\"ResultMsg\":\"SUCCESS\",\"Result\":[{\"UserIdx\":\"4138\",\"Email\":\"testapi#test.co.kr\",\"UserName\":\"test1\",\"Pwd\":\"v+Mb90ZS+Y5Qt9DfuBcJtQ==\",\"Phone\":\"012345678913\",\"AppKey\":\"\",\"LoginDt\":\"9/23/2016 1:12:18 PM\",\"LogoutDt\":\"9/1/2016 10:36:02 AM\",\"RegDt\":\"8/31/2016 9:26:04 AM\",\"DelDt\":\"\",\"KeywordTime\":\"60\",\"KeywordEnabled\":\"1\",\"FastEnabled\":\"1\",\"KeywordStartTime\":\"08:30:00\",\"KeywordEndTime\":\"15:30:00\",\"FastStartTime\":\"08:00:00\",\"FastEndTime\":\"15:30:00\",\"IsFirst\":\"NOT_FIRST\",\"IsFastNews\":\"1\",\"IsKeywordNews\":\"1\",\"KeywordStartDt\":\"\",\"KeywordEndDt\":\"\"}]}")
Could not cast value of type '__NSCFString' (0x10abdf320) to 'NSDictionary' (0x10abe0108).
Any help would be greatly appreciated!
Try this:
do{
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! NSDictionary
print("parse success")
}catch{
print("parse error")
}
Try This Code:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSMutableDictionary
I found this code works.
if let responseData = responseString!.dataUsingEncoding(NSUTF8StringEncoding)
{
let json = try NSJSONSerialization.JSONObjectWithData(responseData, options: .AllowFragments)
print(json)
}
But I don't know the reason exactly.. Thanks all anyway

My swift app fail to convert NSData to Json

I was trying to convert NSData to Json by doing this:
let jdata = getJSON("https://api.myjson.com/bins/16j2i")
do {
let json = try NSJSONSerialization.JSONObjectWithData(jdata, options: []) as! [String: AnyObject]
print(json)
} catch {
print("\(error)")
}
This is the getJSON method
func getJSON(url:String) -> NSData {
return NSData(contentsOfURL: NSURL(string: url)!)!
}
A error says that could not cast value of type '_NSCFArray' to 'NSDictionary'. Any ideas? Please
The root element of your JSON is array not dictionary (Your format looks something like [{...},{...}] ). For fixing this error you need to change the parsing code to:
let json = try NSJSONSerialization.JSONObjectWithData(jdata, options: []) as! [[String: AnyObject]]
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
let convert_array = responseString?.description
// Convert server json response to NSDictionary
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSArray {
print(convertedJsonIntoDict)
}
let data = text.data(using: String.Encoding.utf8)
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any]
Working Fine for Swift 3.1 & Swift 4

iOS SWIFT - JSON object nil after NSJSONSerialization

hello I am trying to read JSON as an array from the server not the dictionary. If I do this
let json: NSArray?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! NSArray
print("json is \(json)")
}
json object comes nil through this code and also I can't access the variable like this json["code"] I have tried this too
NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as! NSArray
But If I don't specify any type and let the variable as AnyObject
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
print("json is \(json["code"]!)")
}
It works But 1st problem here is it prints Optional in the debugger but its least of my worries compared to that I can't do something like this
if json["code"] == 200 {
}
If I do this it says
Binary operator '==' cannot by applied to operands of type Anyobject? and Int
what I want is to get the data in NSArray. I don't want the json variable to be set as AnyObject. Inshort I want this code to work
let json: NSArray?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! NSArray
print("json is \(json)")
}
if its possible. I don't know what I am doing wrong here
json:
{"code":200,"msg":"login success"}
If printing json["code"] works, then json is doubtless a dictionary.
JSONObjectWithData returns AnyObject that is
"I-have-no-idea-what-it-is-but-it-is-some-kind-of-object-and-not-a-value" (thanks to gnasher729 for the more accurate paraphrase of AnyObject)
Since you know the object is [String:AnyObject] cast the type
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! [String:AnyObject]
Then get the code – which is an Int – with
if json["code"] as! Int == 200 {
}
or with optional binding if the key is optional
if let code = json["code"] as? Int {
if code == 200 {
}
}

JSON String to NSDictionary with Swift

I am trying to create a dictionary from data that is held in a server, I receive the data but I cannot convert the data to an NSDictionary, I believe it is held in an NSData Object
let JSONDictionary: Dictionary = NSJSONSerialization.JSONObjectWithData(JSONData!, options: nil, error: &error) as NSDictionary
This line of code is the one giving me the problem, it throws a BAD_EXEC_INSTRUCTION.
MY Question: How can I turn a JSON into an NSDictionary?
Your code does not do any error handling. But it can (and if this data comes from a web service, will) fail in multiple ways.
You have to make sure that your data object actually exists
You have to make sure that the data object can be converted to JSON
You have to make sure that the JSON actually contains a Dictionary
You should use Swifts conditional cast and it's optional binding capabilities.
The optional binding if let JSONData = JSONData checks that JSONData is not nil. The force unwrap (JSONData!) you use might crash if no data could be received.
The optional binding if let json = NSJSONSerialization.JSONObjectWithData checks if the data could be converted to a JSON object. The conditional cast as? NSDictionary checks if the JSON object is actually a dictionary. You currently don't use these checks, you cast the objects as NSDictionary. Which will crash, if the object is not valid json, or if its not a dictionary.
I would recommend something like this:
var error: NSError?
if let JSONData = JSONData { // Check 1
if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &error) { // Check 2
if let jsonDictionary = json as? NSDictionary { // Check 3
println("Dictionary received")
}
else {
if let jsonString = NSString(data: JSONData, encoding: NSUTF8StringEncoding) {
println("JSON String: \n\n \(jsonString)")
}
fatalError("JSON does not contain a dictionary \(json)")
}
}
else {
fatalError("Can't parse JSON \(error)")
}
}
else {
fatalError("JSONData is nil")
}
You could merge check 2 and 3 into one line and check if NSJSONSerialization can create a NSDictionary directly:
var error: NSError?
if let JSONData = JSONData { // Check 1.
if let JSONDictionary = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &error) as? NSDictionary { // Check 2. and 3.
println("Dictionary received")
}
else {
if let jsonString = NSString(data: JSONData, encoding: NSUTF8StringEncoding) {
println("JSON: \n\n \(jsonString)")
}
fatalError("Can't parse JSON \(error)")
}
}
else {
fatalError("JSONData is nil")
}
Make sure to replace fatalError with appropriate error handling in your production code
Update for Swift 2.
Now you must use it inside a try catch block.
do {
let responseObject = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String:AnyObject]
} catch let error as NSError {
print("error: \(error.localizedDescription)")
}
Here jsonResult will give you the response in NSDictionary:
let url = NSURL(string: path)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
println("Task completed")
if(error != nil) {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
})
task.resume()

Resources