ios json parsing sub collection - ios

I have a json collection I am able to parse perfectly fine 1 level deep, but each item in the main collection has a collection in it. I am not quite sure how to access 'item' to get the sub collection like I did with the main collection...
NSString *response = [request responseString];
NSDictionary *json = [response JSONValue];
NSArray *items = [json valueForKeyPath:#"item"];
for (id item in items)
{
mainObject.name = [item objectForKey:#"name"]; //this works fine
// How do I get sub collection from item?
}
Some of the json:
{"item":
{
"available_at" : null,
"created_at" : "2011-12-09T19:52:23Z",
"lo_id" : 30,
"id" : 24,
"merchant_id" : 1,
"order_id" : 25,
"reach_local_link" : null,
"status" : null,
"token" : "12-258847891-1",
"updated_at" : "2011-12-09T19:52:23Z",
"url" : "api/dir/v1/item/12-258847891-1/print",
"subitem1" :
{
"area" : "local",
"broker_id" : "",
"broker_id" : null,
"category" :
{
"category":....
In the example, there could be multiple sub items like subitem1. I need to get the collection of those and have another for loop inside the current one.

item will simply be a dictionary or array if it is one in the JSON object. For example, you should be able to do this:
NSDictionary *subitem1 = [item objectForKey:#"subitem1"];
It's simply a NSDictionary in there, so you can use it as one.
I really recommend logging the Objective-C representation of your JSON object, it makes it easier to work with it:
NSLog(#"%#", json);
Warning
It's strongly recommended to check the type of the objects you load before assuming that they really are dictionaries, strings or arrays. If they aren't, you'll notice that your application is going to crash.

Related

Order of json format is getting changed

Order of json format is getting changed. I need the below format
{
"user_id": "",
"name": "",
"StDate": "07/16/2015 13:00",
"EdDate": "07/16/2015 13:00",
"detailed": [
{
"Stname": ""
},
]
}
What i am getting atlast is
{
"user_id" : "1",
"Detailed" : [
{
“Stname" : ""
},
"EdDate" : "08\/19\/2015 12:25:47",
"StDate" : "08\/19\/2015 12:25:47",
“name” : "",
}
After getting all values i am converting to json. I am using the following code.
NSError *error1;
NSString *jsonString1;
NSData *jsonData1 = [NSJSONSerialization dataWithJSONObject:dictjson1
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (! jsonData1) {
NSLog(#"Got an error: %#", error1);
} else {
jsonString1 = [[NSString alloc] initWithData:jsonData1 encoding:NSUTF8StringEncoding];
NSLog(#"converted json string is %#",jsonString1);
}
Please advice.
JSON has two structures: objects and arrays. Arrays are indexed by integers, and ordered. Objects are indexed by strings, and unordered. You can't enforce order on JSON objects; it is implementation-dependent. If you need to access object attributes in a certain order, enumerate the keys in this order in an array.

iOS Game Center send json in match data

I am trying to send JSON data in matchData object when a user end its turn. If I check the json before sending it is valid and looks like,
JSON:
{
"p1score" : "0",
"turn" : "0",
"pb1" : "BPS1120|2231|3422|4213|5244|6135",
"player2" : "0000177110",
"player1" : "0000177110",
"p2score" : "0",
"movements" : "MVS2242",
"pb2" : "BPS1630|2511|3522|4543|5534|6625",
"moves" : "30"
}
Prepares the data for sending,
NSData *matchData = [[NSString stringWithFormat:#"%#",realMatchData] dataUsingEncoding:NSUTF8StringEncoding];
realMatchData contains the above json string.
But if convert the matchData back to string again to check what is being sent using,
NSString *str = [[NSString alloc] initWithData:matchData encoding:NSUTF8StringEncoding];
I get back the following json string
{
"moves" : "30",
"turn" : "0",
"player2" : "G:0000177110",
"p1score" : "0",
"player1" : "G:0000177110",
"movements" : "MVS",
"p2score" : "0"
}
keys pb1 and pb2 are missing.
I event tried to pass the values of pb1 and pb2 as nested json but problem remains the same, they keys are missing when sending data.
Is the right way to share the game state or should I use some other approach to share data ?
Thanks.
This does not answer the question exactly, but it may solve the problem, and the asker asked for an example. Apple provides its own JSON serialization which produces an NSData object from JSON serializable objects like NSNumber, NSArray, NSString, NSDictionary, etc.
NSMutableArray* matchArray = [NSMutableArray array];
/*
Fill the match array with the appropriate objects to represent your game state...
You've presumably already done this in order to get that string object...
*/
NSData* matchData = [NSJSONSerialization dataWithJSONObject: matchArray
options: 0 //pretty sure all the options here are irrelevant for our purposes
error: NULL]; //pass in a pointer to an NSError if you are interested in the error
//end the turn or do whatever one does in a non-turn-based match with matchData as the data object

Xcode - Getting object out of an array within an array

I have a JSON array(dictionary?) of objects that are themselves an array. I need to find a value within one of these arrays so that I can compare it later. Part of my JSON data:
[
{
"Name": "Exhibitor",
"Url": "api/congress/exhibitor",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Workshop",
"Url": "api/congress/workshop",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Speaker",
"Url": "api/congress/Speaker",
"ResourceType": "Data",
"LastMod": 1389106977
},
]
My method receives a table name as a parameter and returns a time stamp. How would I receive the time stamp (1389106977) for the table "workshop" for example? This seems so simple but I cannot work it out for 'nested' arrays/dictionaries.
Thanks,
edit:
This is the my code with trojanfoe's added to it.
NSError* localError;
NSMutableArray *syncDataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (syncDataArray)
{
NSNumber *lastMod = nil;
for (NSDictionary *dict in syncDataArray)
{
NSLog(#"current table is: %#", dict[#"Name"]);
if ([tableName isEqualToString:dict[#"Name"]])
{
lastMod = dict[#"LastMod"];
//break;
}
}
NSLog(#"LastMod = %#", lastMod);
}
else
{
NSLog(#"syncDataArray is empty");
}
This works perfectly and makes sense
The JSON data looks like an array of dictionaries, so you can iterate over the array and test for the "Name" entry:
NSArray *jsonData = ...; // You have converted JSON to Objective-C objects already
NSNumber *lastMod = nul;
for (NSDictionary *dict in jsonData) {
if ([#"Workshop" isEqualToString:dict[#"Name"]]) {
lastMod = dict[#"LastMod"];
break;
}
}
if (lastMod) {
// You found it
}
(Note I am not certain the type of object used to store the "LastMod" object, so you might need to do some debugging to find out).
EDIT If you make extensive use of this data you should immediately convert the JSON data into an array of (custom) model objects, which will make it easier to manipulate the data as your app becomes more complex.
You have an array for dictionaries so it would look something like :
NSNumber *timestamp = [[JSON objectAtIndex:index] objectForKey:#"LastMod"];
NSNumber *timestamp = response[1][#"LastMod"];

how to get JSON object from server as it (in the same order) iPhone

Is there any way to get JSON object from the server in the same order??
For example when i fitch using browser my JSON object return like this:
{
"23": {
"numberOfRecords": "3",
"startDate": "27/11/2013",
"endDate": "31/12/2014",
"question": "How do you rate the new MenaME Portal ?",
"voteScale": "5",
"questions": {
"option1": {
"value": "1",
"option": "Poor",
"voteResult": "50.000"
},
"option2": {
"value": "2",
"option": "Acceptable",
"voteResult": "0.000"
},
"option3": {
"value": "3",
"option": "Good",
"voteResult": "0.000"
},
"option4": {
"value": "4",
"option": "Very Good",
"voteResult": "0.000"
},
"option5": {
"value": "5",
"option": "Excellent",
"voteResult": "50.000"
}
},
"selectedAnswer": "0",
"voteAnswered": "0",
"votes": "6"
}
}
after parsing it with [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error]
the object returned like this :
{
23 = {
endDate = "31/12/2014";
numberOfRecords = 3;
question = "How do you rate the new MenaME Portal ?";
questions = {
option1 = {
option = Poor;
value = 1;
voteResult = "50.000";
};
option2 = {
option = Acceptable;
value = 2;
voteResult = "0.000";
};
option3 = {
option = Good;
value = 3;
voteResult = "0.000";
};
option4 = {
option = "Very Good";
value = 4;
voteResult = "0.000";
};
option5 = {
option = Excellent;
value = 5;
voteResult = "50.000";
};
};
selectedAnswer = 0;
startDate = "27/11/2013";
voteAnswered = 0;
voteScale = 5;
votes = 6;
};
}
Is there any way or framework to get the object as it (in the same order returned from the server) ??
Dictionaries, both in JSON and NSDictionary, are unordered, meaning that it is irrelevant which order you see things in the log. This is defined in the JSON specification and the documentation for NSDictionary.
If it actually matters what order things are displayed in, then either the API you are linking to isn't using correct JSON, or you're doing something wrong in your app. To help with those situations you can use several of the sorted NSDictionary implementations that are around.
Can I ask why you want to ensure the dictionary is maintained in the correct order?
I understand in some cases (mine) an ancient JSON -> XML web service was being called by my app and the client refused to adjust the service so it could accept unordered JSON (valid json) but if you're writing the app, why do you need to ensure that it is in order?
I have a NSMutableDictionary subclass that keeps objects added by setObject:forKey in the order you call the method that can be found here.
It works by storing a NSMutableOrderedSet of keys within the dictionary and then overrides the keyEnumerator method to return an enumerator based on the ordered set
- (NSEnumerator *)keyEnumerator
{
return [self.orderedSetOfKeys objectEnumerator];
}
You could modify the NSMutableDictionary subclass i created to expose the NSMutableOrderedSet in the public header and then modify this set yourself to get an ordered version of your dictionary.. For example:
NSDictionary *JSONWebServiceDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
LNOrderedMutableDictionary *orderedDictionary = [[LNOrderedMutableDictionary alloc] initWithDictionary:JSONWebServiceDictionary];
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]]; //All the keys you are expecting and the order you want them in..
orderedDictionary.orderSet = order; //orderSet does not exist.. it is currently called `array` and not exposed in LNOrderedMutableDictionary.h
I haven't tested the code above but unless you want to create or modify an existing JSON parser then it seems that it is your only option..
If you did want to modify an existing parser then it might just be as simple as replacing dictionary instances with LNOrderedMutableDictionary to keep everything in order.
Another idea to expand the above sample code could be to replace
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]];
with an array returned in the JSONWebServiceDictionary dictionary as arrays keep their order when parsed from JSON so maybe you could do this?
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:[JSONWebServiceDictionary objectForKey:#"keyOrderArray"]]];
Look at what you have. If you test the result you got back from JSONObjectWithData (which we'll assume was declared as id jsonObject)
if ([jsonObject isKindOfClass:[NSDictionary class]) { ...
or
NSLog(#"The object type is %#", [jsonObject class]);
you will find that it is indeed an NSDictionary (or perhaps an NSMutableDictionary). That dictionary, as you can see from the dump (or infer from the nearly identical JSON) contains a single entry with a key of "23".
So let's cast the jsonObject to an NSDictionary and reference it:
NSDictionary* jsonDict = (NSDictionary*) jsonObject;
NSDictionary* entry23Dict = [jsonDict objectForKey:#"23"];
Now, if you NSLog entry23Dict you will discover it contains all of the above, absent the { 23 = ... } outermost dictionary.
You can then access, say, "questions" with
NSDictionary* questDict = [entry23Dict objectForKey:#"questions"];
From there the individual "option1", "option2", ... "option5" dictionaries can be accessed in a similar fashion. You simply proceed one layer at a time -- don't get overwhelmed by the entire structure. (It's often helpful, when you're first learning, to NSLog each "layer" as you "peel" it out of the containing structure.)
And, of course, you have all the standard facilities that are available to NSDictionary objects (and NSArray objects, should your JSON contain any [..] arrays). For instance, you can iterate on the keys of the dictionary with
for (NSString* key in jsonDict) {
NSLog(#"This entry's number is %#", key); // For the above will print "23"
NSDictionary* numberedDict = jsonDict[key]; // Using the "new" form of dictionary access
NSString* endDate = numberedDict[#"endDate"]; // Ditto
NSLog(#"The end date is %#", endDate);
}
This is a fairly common problem. It's also probably the most annoying part about iOS. (java doesn't have this issue at all). If you want to get back objects, take a look at restkit.org Specifically this answer may help: https://stackoverflow.com/a/8284343/836450

Need to prefix JSON document being generated from NSMutableDictionary in iOS

I am able to successfully generate a JSON document by iterating through a NSMutableDictionary. This NSMutableDictionary in turn, contains two values that are also NSMutableDictionary's, the keys of which are reports, and results respectively.
The code that constructs the JSON document is as follows:
NSMutableDictionary *jsonDoc = [NSMutableDictionary dictionary];
[jsonDoc setObject:results forKey:#"results"];
[jsonDoc setObject:reports forKey:#"reports"];
NSError *ierror = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDoc options:NSJSONWritingPrettyPrinted error:&ierror];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSON Output: %#", jsonString);
and my JSON output looks like this:
JSON Output: {
"results" : [
{
"date" : "2012-12-25T16:58:25",
"name" : "Test 1",
"result" : "Fail"
},
{
"date" : "2012-12-25T16:58:33",
"name" : "Test 2",
"result" : "Pass"
},
{
"date" : "2012-12-25T16:58:38",
"name" : "Test 3",
"result" : "Pass"
},
{
"date" : "2012-12-25T16:58:45",
"name" : "Test 4",
"result" : "Fail"
}
],
"reports" : [
]
}
I am very happy with the output I am getting. However, what I would like to do now is to prefix the data I am outputting with additional details that would go after the JSON Output: { but before "results". The additional details are simply NSString values like "Name:", "Address", "City", "Province", "Postal Code", etc. How would I do this given the code structure that I have presently? The catch is that I would like these details to be part of the original JSON object when I am initially building the JSON object, and not simply when I am outputting to the console.
Just call setObject:forKey: for each of the key/value pairs you want to add to the jsonDoc dictionary. It doesn't matter whether you put them above or below the two calls you have in your question since dictionaries are unordered.

Resources