Orderer Key-Value structure in objective c [duplicate] - objective-c

I have the following situation:
NSDictionary *params = #{
#"Checkout" : #{
#"conditions" : #{#"Checkout.user_id" : #1},
#"order" : #{#"Checkout.id" : #"DESC"}
},
#"PaymentState" : #[],
#"Offer" : #[]
};
This dictionary contains params for a webservice request passing a JSON string with the webservice URL. I get the JSON string using NSJSONSerialization class, like this:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
The problem is: jsonString "keys" is ordered differently from the original params dictionary keys order, like this:
{
"Offer":[],
"PaymentState":[],
"Checkout":{
"conditions":{"Checkout.user_id":6},
"order":{"Checkout.id":"DESC"}
}
}
That is, the "PaymentState" and "Offer" keys come first in jsonString, and i need maintain
the original order. This is very important, like this:
{
"Checkout":{
"conditions":{"Checkout.user_id":6},
"order":{"Checkout.id":"DESC"}
},
"Offer":[],
"PaymentState":[]
}
So guys, how can i do that??

I use OrderedDictionary from CocoaWithLove whenever I need to keep the order of my dictionary keys.
Basically, OrderedDictionary contains an NSMutableDictionary and an NSMutableArray for the keys inside it, to keep track of the order of the keys. It implements the required methods for subclassing NSDictionary/NSMutableDictionary and just "passes" the method call to the internal NSMutableDictionary.

According to the JSON spec a JSON object is specifically unordered. Every JSON library is going to take this into account. So even when you get around this issue for now, you're almost certainly going to run into issues later; because you're making an assumption that doesn't hold true (that the keys are ordered).

While NSDictionary and Dictionary do not maintain any specific order for their keys, starting on iOS 11 and macOS 10.13, JSONSerialization supports sorting the keys alphabetically (see Apple documentation) by specifying the sortedKeys option.
Example:
let data: [String: Any] = [
"hello": "world",
"a": 1,
"b": 2
]
let output = try JSONSerialization.data(withJSONObject: data, options: [.prettyPrinted, .sortedKeys])
let string = String(data: output, encoding: .utf8)
// {
// "a" : 1,
// "b" : 2,
// "hello" : "world"
// }

Related

JSON: Understanding format in Objective-C

Given the following JSON payload I would like to extract "023" from keyB->key2:
JSON Payload:
{
"keyA" : {"lon": 139, "lat" : 35},
"keyB" : [ {"key1" : "value", "key2" : "023"} ]
}
This is the code I apply:
NSDictionary * subResults = jsonResult[#"keyB"];
NSLog(#"VALUE: %#", [subResults valueForKey:#"key2"])
However the value is printed as following:
VALUE: (
023
)
I want to get rid of the brackets "(". Am I approaching the extraction in the wrong way?
First, your json as given is not valid son :( you have a quote to many. If we escape it like this:
{"keyA":{"lon":139,"lat":35},"keyB":[{"key1":"value\" clouds","key2":"023"}]}
Then, it's ok.
Now, what you have here is an son object, containing 2 keys (A and B). And KeyB is associated with a json Array
meaning :
jsonResult[#"keyB"];
Does not return a NSDictionnary but a NSArray, containing 1 NSDictionary.
Now if you try to get the value "023", you should use
NSString str = jsonResult[#"keyB"][0][#"key2"]; // return "023"
and maybe
int twentyThree = str.intValue;
The brackets show the value you want is inside an array.
NSData strAsData = …;
NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:strAsData options:0 error:nil];
NSArray *subResults = jsonResult[#"keyB"];
NSDictionary *subSubResults = subResults[0];
NSLog(#"VALUE: %#", subSubResults[#"key2"]);
Because the array only has one item you can use a call to -lastObject or -firstObject

How to get value from json with duplicate key?

I looked for a long time for an answer to this and couldn't find anything. Perhaps it is because I don't know how to ask the question as I am new to json. Essentially I am a new ios developer and am trying to learn how to access and use json data. Below is a portion of the json I am using:
{
"status": null,
"data": {
"1088": {
"nid": "1088",
"title": "RE 1 (2000)",
"articles": [
{
"nid": "2488",
"title": "Copyright Page"
},
...
etc.
my confusion is that there are two layers with the value title. So when I'm using something like
self.dict = [self getDictionaryFromJson]; and have saved the json in a dictionary, then I go to use
self.mainTitle = [self.dict objectForKey:#"title"]; and it would presumedly give me back RE 1 (2000). But then I also want to get back the secondary title which is Copyright Page so then i would do self.secondaryTitle = [self.dict objectForKey:#"title"];???
Anyways, my confusion is that I would think it would just again give me back RE 1 (2000) because there is no change to the call and so I don't know how to access the next item with the same key.
Perhaps I am sure the solution is simple I just don't quite understand what I need to do.
You are neglecting the hierarchy of the data which is mapped into the dict - log it to check.
So, to get the first title (RE 1 (2000)), you would do:
NSString *title = [self.dict valueForKeyPath:#"data.1088.title"];
to drill down through the levels in the JSON (and thus the dictionary). And the same approach applies for deeper nested items (though you can't always use valueForKeyPath: because it won't do what you expect with arrays...).
The JSON you posted contains nested arrays (denoted by square brackets []) and dictionaries (denoted by curly brackets {}). You can convert JSON to an NSDictionary using NSJSONSerialization:
NSData *data = ... // Get JSON Data
self.dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.mainTitle = [[[self.dict objectForKey:#"data"] objectForKey:#"1088"] objectForKey:#"title"]
self.secondaryTitle = [[[[[self.dict objectForKey:#"data"] objectForKey:#"1088"] objectForKey:#"articles"] objectAtIndex:0] objectForKey:#"title"]
For more info about JSON, you can read the spec.

Converting NSStrings to Json

I have search a lot ,i did found many answers, but not the specific one i need-which is so simple.
I want to take 2 different NSString that the user type, and create a json from them to send to server .
I wrote this :
-(id)stringToJason:(NSString*)stringData
{
NSData *data = [stringData dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
return json;
}
But there is something i dont get. this return 1 nsstring as json.
How would i take 2 different NSStrings, and create from them together ,the json ?
Lets say: userName:me (when each one is comes from text field)
json should look like :
"Username": "me",
"Firstname": "r",
"Lastname": "k",
If you're wanting to produce JSON that looks like:
{
"Username":"me",
"Firstname":"r",
"Lastname":"k"
}
Where r and k are values taken from the textfields, you could write a method along the lines of this:
-(NSData*)jsonFromFirstName:(NSString*)firstName andLastName:(NSString*)lastName
{
NSDictionary* dic = #{#"Username" : #"me", #"Firstname" : firstName, #"Lastname" : lastName};
// In production code, _check_for_errors!
NSData* json = [NSJSONSerialization dataWithJSONObject:dic options:0 error:nil];
return json;
}
You would call this method, passing the r (firstName) and k (lastName) values to it. It would construct a dictionary that has the structure of the desired JSON, with the desired values. You'd then use NSJSONSerialization's -dataWithJSONObject:options:error selector to convert the dictionary into a JSON data object (stored in an NSData object). You then have the data to send to the server!
The dictionary created in the first line of the method could be expanded as much as you desired, and you could even pass in non-strings (such as numbers, arrays, or even other dictionaries!).

JSON return value incorrectly parsed in objective C: iOS

{"Overviews":
[
{"AAAA": [
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
],
"BBBB": [
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
]
}
]
}
Hi I used SBJson to parse this json. When I assigned NSArray *json = [jsonObject valueForKey:#"Overviews"];. The hierarchy of data didn't go well. I used one NSDictionary, 2 NSArray and 1 NSString to parse Generala.
My goal is to parse the data "Generala" like this:
NSDictionary *data = [overviews valueForObject:#"AAAA"];
NSString *generals = [data valueForObject:#"Generala"];
What have I done wrong in the json file? Thanks in advance.
You've got superfluous arrays in there. Overviews is an array with one element in - a dictionary. It should just be the dictionary. The same applies for AAAA and BBBB - they are arrays containing a single dictionary, when they should just be dictionaries.
Basically, just delete all of the square brackets in your JSON.
NSArray *dataArray = [overviews objectForKey:#"AAAA"];
NSDictionary *dataDict = [dataArray objectAtIndex:0];
NSString *generals = [dataDict objectForKey:#"Generala"];
This will get you to the correct value, But as you can see I had to "Hard code" the index "0". You would want some logic in there to get to the specific array.
or Change your json to:
{"Overviews":
{"AAAA":
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"},
"BBBB":
{"Generala": "sometext",
"Generalb": "sometext",
"Generalc": "sometext"}
}
}
and use:
NSDictionary *dataDict = [overviews objectForKey:#"AAAA"];
NSString *string = [dataDict objectForKey:#"Generala"];
Your source is a dictionary of one entry, which entry contains an array of one entry, which entry contains a dictionary of two entries, which entries each contain an array of one entry, which entry contains a dictionary of three entries.
I suspect this is exactly how the JSON parser parsed it.

Parsing a JSON array into a NSDictionary

I'm working with the Weather Underground API to make an app and I've hit a snag while parsing the block relating to severe alerts. The JSON uses key-value pairs that have sub key value pairs -- which haven't been a problem for me, as I can make subsequent NSDictionaries out of those -- but the entry for severe alerts has proven problematic. See below:
"alerts": [
{
"type": "WAT",
"description": "Flash Flood Watch",
"date": "3:13 PM EDT on April 28, 2012",
"date_epoch": "1335640380",
"expires": "8:00 AM EDT on April 29, 2012",
"expires_epoch": "1335700800",
"message": "\u000A...Flash Flood Watch in effect through Sunday morning...\u000A\u000AThe National Weather Service in Charleston has issued a\u000A\u000A* Flash Flood Watch for portions of northeast Kentucky... (Note: I trimmed this for length's sake),
"phenomena": "FF",
"significance": "A"
}
]
The "alerts" pair differs from others I've been able to parse because it has this [ ] bracket surrounding the sub-values and I'm not sure how to clear it so I can access the subvalues. In the other examples I've been able to parse, it only has the { } brackets, and not both the { } and [ ] brackets. For reference, the brackets are always present -- even when there are no severe weather alerts... in that instance the "alerts" pair returns the brackets [ ] with no sub-pairs present.
Is there a way I can remove the [ ] brackets from the NSDictionary, or otherwise ignore them? Any advice would be appreciated!
For reference and troubleshooting help, here's how I'm parsing the rest of the JSON document successfully:
1) Create an NSDictionary from the raw JSON
//Process Weather Call
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
2) Create subsequent dictionaries for nested json pairs
NSDictionary *current_observation = [json objectForKey:#"current_observation"];
3) Assign values
NSString* weather;
weather = [current_observation objectForKey:#"weather"];
So the end result would be a string that says "Partly Cloudy" or something, along with numerous related weather values that I haven't shown. These parse successfully because they only have the scope brackets { }, and not the [ ] brackets.
The brackets means the Json data there are in an array. You can parse it as following
NSArray *alertArray = [json objectForKey:#"alerts"];
now you should loop through all alerts and parse them (in your case it's only 1, but it could be more in another json string):
//parse each alert
for (NSDictionary *alert in alertArray ){
NSString* description = [alert objectForKey:#"description"];
//etc...
}
Okay, I got it working -- and I wanted to provide an example here because I ended up having to build on the advice #Lefteris gave to get it working.
I ended up having to pass the json array first as an NSArray, and then I converted that into an NSDictionary with the first element of the array. Everything afterwards worked as #Lefteris described.
So, in the end, here's what I've got:
NSArray *alerts = [json objectForKey:#"alerts"];
NSDictionary *alertDict = [[NSDictionary alloc] init];
//Check that no alerts exist to prevent crashing
if([alerts count] < 1) {
NSLog(#"No Alerts Here!");
type = nil;
...
}
else //Populate fields
{
alertDict = [alerts objectAtIndex:0];
for (NSDictionary *alert in alertDict)
{
NSLog(#"Printing alert!");
type = [alertDict objectForKey:#"type"];
...
}
}
This got me up and running with a single array iterate -- going on I expect I can simply iterate through the array since I know the count and handle any additional alerts. Thanks again for the help!