NSJSONSerialization messing up resulting NSDictionary - ios

I'm having trouble parsing the json output from a web service. I am using NSJSONSerialization to parse the output into an NSDictionary. Also using AFNetworking by subclassing AFHTTPSessionManager. For now the response serialiser is AFHTTPResponseSerializer which returns NSData
Here's the code I'm using:
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:&err];
Pretty straightforward. And the err object is nil so the conversion works fine.
BUT: the result I get straight from the web service is this:
"address":
{
"address1": "Ivy House",
"address2": "Sandy Lane",
"city": "Rush",
"postCode": null,
"email": "notknown#whatever.com",
"telephone": "18437584",
"mobile": null,
"smsAlert": null,
"county": "Dublin",
"country": "Ireland",
"websiteAddress": "www.example.com"
},
The result I get after printing the content of dict is this:
address = {
address1 = "Ivy House";
address2 = "Sandy Lane";
city = Rush;
country = Ireland;
county = Dublin;
email = "notknown#whatever.com";
mobile = "<null>";
postCode = "<null>";
smsAlert = "<null>";
telephone = 18437584;
websiteAddress = "www.example.com";
};
The issue is that the resulting NSDictionary does NOT have double quotes and so saving the NSDictionary to disk in plist format FAILS!
I have also tried using AFJSONResponseSerializer which returns NSDictionary but the contents are the same as above!
Where's the issue here?
Thanks in advance.

The problem here doesn't seem to be related to double quotes at all. When printed, NSDictionary (as well as other Foundation objects) drop enclosing double quotes when they are not needed (e.g. when no spaces or special characters in the string).
Now, the likely problem preventing you from serialising your NSDictionary to a property list is presence of nulls in the JSON and, consequently, in NSDictionary. According to documentation:
Property list objects include NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber objects.
Whereas nulls from JSON will be represented as instances of NSNull, thus making your NSDictionary an invalid Property List.

NSDictionary has different structure then JSON string. So when you parse a JSON string to NSDictionary you should not expect quotes.
You can save the JSON data and parse it again on runtime.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"yourfilename.dat"];
// Save it into file system
[data writeToFile:dataPath atomically:YES];

Related

iOS JSON Parsing, Format Issues

So I was working on a project that required me to work with some JSON, I was running into a few issues regarding the best way of representing things. First of, this is how the JSON looks:
"phoneList": [
{
"phoneReason": "End of Contract",
"phoneType": [
{
"id": 5,
"phoneType": "Android Smartphone"
}
]
}
]
I want to know the most appropriate way of representing this.
For example, I do know that that my phoneReason will just be a simple NSString while my phoneType is actually a NSArray. However,I wasn't sure how to represent a)the id, I know this is an integer, but should this be an NSInteger or an NSNumber and b)could someone point me in the direction of some sample code where I can understand how to model a dictionary object containing an integer and a string and also where I can understand how to model an array of dictionaries.
My other question is also similar in that say I'm actually posting something, how do I model this, specifically say for like dictionary type (JSON Curly Brace)objects that contain a number/integer and a string.
For example, this is the JSON I'm trying to model and then do something like this:
"phoneReason": "Upgrade",
"phoneInfo": {
"id": "2"
},
//And then I want to pass ID
-(void) createOurRequest:(NSNumber *)id {
NSDictionary *myDictionary = #{
#"phoneReason" : [NSString stringWithFormat:#"%i", s elf.dat.reason],
//How do I then represent the phoneInfo element exactly?
};
Sorry, for the clumsy question, would really appreciate any guidance on modeling JSON in iOS or just generally.
I'm assuming you're asking questions a) and b), and also how to model a JSON.
a) The unfortunate thing with Obj-C is that all collection elements have to be objects. Integers are value types, so they will need to be converted to NSNumbers to work. However, if you're parsing a JSON string, the builtin JSON parser does it for you. I'll describe it below.
b) The model is based on the JSON. You describe the object collection and the parser will determine the model for you. In your example, you would have a NSDictionary<NSString *: NSArray<NSDictionary<NSString *: id>*>*>. The innermost element has value of id because you can either have an NSString ("End of Contract") or an NSArray ("phoneType": [ { "id": 5, "phoneType": "Android Smartphone" } ])
Of course, the model is defined by your JSON, so if you run it through a parser, you get a structured object. You can access each element based on your model (object[#"phoneList"][#"phoneReason"]).
The class method to use is:
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError **)error
Where you pass it a NSData representation of your string, options (or 0), and a NSError pointer (error*). You get back a parsed JSON with the proper structure you defined.
NSDictionary *parsedJSONObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL
I have no options to use and I know there will be no error, so I pass nothing for those parameters. The resulting object will be in whatever structure your JSON is.
Using the objects and the json layout you provided in your first example, this is how I would go about creating the dictionaries and arrays to get the json in the format you specified. Hopefully this helps make it a little clearer for you.
// example constructor method
-(void) jsonStringWithPhoneReason:(NSString*)reason phoneId:(NSInteger)phoneId phoneType:(NSString*)phoneType
{
// create device detail dictionary
NSDictionary *deviceOneDetail = #{
#"id" : #(phoneId), // <- set phone id as NSNumber
#"phoneType" : phoneType // <- set your string phone type
};
// create device dictionary
NSDictionary *deviceOne = #{
#"phoneReason" : reason, // <- set your phone reason string
#"phoneType" : #[deviceOneDetail] // <- set your phone type dictionary within an array
};
// create phone list dictionary with any device dictionaries you want to add
NSDictionary *phoneListDict = #{
#"phoneList" : #[
deviceOne, // <- add your device to the phone list array of dictionaries
// deviceTwo...
]
};
NSString *jsonString = [self convertToJsonString:phoneListDict]; // <- convert the dictionary into a json string and use however you wish
// your json string should now look like this assuming you pass 'End of Contract', 5 & 'Android Smartphone' as arguments to this method
// {"phoneList":[{"phoneReason":"End of Contract","phoneType":[{"id":5,"phoneType":"Android Smartphone"}]}]}
}
-(NSString*) convertToJsonString:(NSDictionary*)dictionary
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:0 // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (error)
{
NSString *errorDesc = [NSString stringWithFormat:#"Error creating json data from dictionary: %#", error.localizedDescription];
NSLog(#"ERROR: %#", errorDesc);
jsonData = nil;
return nil;
}
NSString *returnString = nil;
if(jsonData != nil)
{
returnString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return returnString;
}

iOS: Parsing dictionaries from a string into NSMutableDictionary / NSMutableArray

Is there a fast way to parse dictionaries in iOS from a sting, with the format:
property1: value1
property2: [ property3: value3 ; property4: [property5: value5] ]
property6: "and so on"
The string would contain something like:
NSString *str = #"property1: value1 property2: [ property3: value3 ; property4: [property5: value5]] property6: "and so on" ";
and would generate a root NSMutableDictionary / NSMutableArray element, containing additional
NSMutableDictionary / NSMutableArray elements
Thanks in advance
why not using json format ?
replace this with this
[ {
] }
; ,
and you will be able to use jsonparser : NSJSONSerialization
No. That isn't any standard format. It looks like a bizarro version of JSON. If you want to parse this format, you'll need to either find some third-party parser or wrote one yourself.
Your JSON string is invalid. Please use http://jsonlint.com to verity if your JSON string is valid or not. Now, given your JSON is valid, this is how you can read string JSON into a NSDictionary:
NSString *strData = #"{\"property1\":\"value1\",\"property2\":{\"property3\":\"value3\",\"property4\":\"value4\"}}";
NSData *data = [strData dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"%#", json);

Get multiple values from a web service

I have a webservice, in which the parameter "upload_images" have more than one value. How can i get that values. I am using SBJson. Here is my response
{
"node_title": "thk",
"category": "Boating",
"description": "Fg",
"link": "",
"nid": "446",
"post date": "Mon, 11/25/2013 - 07:04",
"upload_images": "http://prod.kyzook.com/?q=sites/prod.kyzook.com/files/styles/medium/public/2013-11-25%2007%3A03%3A25%20%2B0000.png&itok=WIBTqzbC, http://prod.kyzook.com/?q=sites/prod.kyzook.com/files/styles/medium/public/2013-11-25%2007%3A03%3A58%20%2B0000.png&itok=AhoLUnou"
}
If I understand your question correctly, upload_images contains a string of comma-separated URLs and you want to extract them.
You can easily achieve this using NSString's method componentsSeparatedByString, for instance
NSString *uploadImages = response[#"upload_images"];
NSArray *imageURLs = [uploadImages componentsSeparatedByString:#", "];
where I assumed response to be a NSDictionary object holding the parsed response.
you can get the the "upload_images" as the string and can convert in the array using componentsSeparatedByString: method
NSString *uploadImages = [response objectForKey:#"upload_images"];
NSArray *imageUrlArray = [uploadImages componentsSeparatedByString:#", "];

JSON Parsing Returns Null For Large Values Only

I'll keep this brief. I'm using this code to parse JSON from a local file into an array of objects:
-(void)populateData
{
NSString* sourcePath = [[NSBundle mainBundle]pathForResource:#"ships" ofType:#"json"];
//get json string
NSString* JSONData = [[NSString alloc] initWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
NSData* data = [JSONData dataUsingEncoding:NSUTF8StringEncoding];
//put json in array
ships = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(#"%#", ships);
}
(Note: only showed one for the sake of brevity, there's ~20 entries in each one)
This method works for JSON formatted like this:
[
{
"name": "Santa Maria",
"operator": "Kingdom of Spain",
"flag": "flag_spain"
}
]
It returns null for JSON formatted like this:
[
{
"name": "Santa Maria",
"operator": "Kingdom of Spain",
"flag": "flag_spain",
"launched": "November 19, 1890",
"fate": "Destroyed in Havana, Cuba in Feburary 1898."
"cost":"$4,677,788.75",
"image": "maine_img",
"image_attribution": "Image is in the public domain."
}]
I haven't the faintest idea of why the smaller one works while the larger one doesn't. Any help would be appreciated.
There is a comma missing after:
"fate": "Destroyed in Havana, Cuba in Feburary 1898."
It's due to a syntax error on this line:
"fate": "Destroyed in Havana, Cuba in Feburary 1898."
(missing comma at the end)
There are tools to spot this kind of errors. For instance, http://jsonlint.com. This one seems to have better error messages http://jsonformatter.curiousconcept.com/.
And excuse me, but converting from NSData to NSString and then back to NSData is just pointless. Just call dataWithContensOfFile: and be done with it.

Parsing JSON response with multiple objects

I've got a question regarding parsing a JSON response within iOS5.
Currently, I'm following this guide here to help me parse the JSON response returned from a third-party mapping service.
Everything works, except that the JSON response returned by the third-party server is somewhat different from the one shown in the guide itself.
In a nutshell, the overall structure of the entire JSON response looks something like this:
{
"directions": [....],
"messages": [....],
"routes":
{
"features": [
{
"attributes": {....},
"geometry":
{
"paths": [....]
}
}
]
}
}
This is the actual JSON query URL.
By using this line of code,
NSDictionary * jsonResponse = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
I am able to sucessfully get the jsonResponse dictionary to report that it has 3 key/value pairs, but my ultimate goal is to retrieve the array stored in 'routes.features.geometry.paths'.
This is my current code block that gets the final set of array values:
NSDictionary * jsonResponse = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSArray * jsonArray = [jsonResponse valueForKeyPath:#"routes.features.geometry.paths"];
jsonArray = [jsonArray objectAtIndex:0];
jsonArray = [jsonArray objectAtIndex:0];
I was wondering if anyone might have a better idea of how I should go about doing this in a more elegant fashion?
Thanks a lot in advance!
You can't just use it as JSON object because it will be working as JSON (Plain String) and you need to parse it so for your problem you can do like this to directly go to paths
NSArray *arr = [[[[jsonResponse objectForKey:#"routes"] objectForKey:#"features"] objectForKey:#"geometry"] objectForKey:#"paths"];
Now you can access your paths data from "arr" array
UPDATE:
NSArray *arr = [[[[[jsonResponse objectForKey:#"routes"] objectForKey:#"features"] objectAtIndex:0] objectForKey:#"geometry"] objectForKey:#"paths"];
as features element is an Array so traverse array first then goto its elements

Resources