Dictionary put into Array gets shredded - ios

I try to send data to the server. Server waits from my this structure among other:
{
...
"card": [
{
"child": {...},
"parent":{...}
},
{
"child": {...},
"parent":{...}
}
],
[...],
[...]
}
So it should be Dictionary ({...}) placed into another Dictionary ({"child":..., "parent":...}), placed into an Array ("card": []), and this array is a cell, the final API JSON contains many of such cells.
I realize this structure by something like this:
NSDictionary *card = #{#"key1" : #"val1", #"key2" : #"val2", #"key3" : #"val3"};
NSDictionary *pair = #{#"parent" : card, #"child" : card};
NSArray *cards = [NSArray arrayWithObjects: pair, pair, nil];
After this I add cards Array into Dictionary with other auth data and send it to the server:
[self.userAuthData setObject: cards forKey:#"card"];
And I see in the server logs that data was shredded: http://monosnap.com/image/UbLPA0AK0eotAvG12o1ML4702xy0aj.png
But, if I use Dictionary cards instead of Array cards, everything is ok: http://monosnap.com/image/IzenpFc3Gik01UYhyRYtGFHmxBpCpC.png
What's wrong with idea to store Dictionary in an Array? Why it gets shredded?

Ok, answer is here: AFNetworking posts JSON arrays as multiple single-entry dictionaries
I just added a line in my ApiClient.m
_sharedClient.requestSerializer = [AFJSONRequestSerializer serializer];

Related

Getting specific index such students names from json data

I am developing simple app in iOS that gets data web api my code returned json data correctly but when I want to specific for example student name from json returned null.
Here is my data :
{
Sudent(
{
{"id":"20",
"name":"Alan",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"London"},
{
"id":"40",
"name":"John",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"usa"},
"id":"50",
"name":"Nora",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"kenya"},
})}
Here my code that gets data as json and stored NSMutableArray named Student:
-(void)proxydidFinishLoadingData:(id)data InMethod:(NSString*)method
{
if ([method isEqualToString:#"getstudentdata"]){
defaultDict = [[NSMutableDictionary alloc]init];
[defaultDict addEntriesFromDictionary:[NSJSONSerialization JSONObjectWithData:[data dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]];
Student = [defaultDict objectForKey:#"data"];
}
}
this codes it works ok and correctly and returned json data but the problem is when I want to get specific index such as names of students it is not work it returns null value.
the code that does this work is here:
NSMutableDictionary *response = [[defaultDict valueForKey:#"data"] mutableCopy];
NSString *name = [[response valueForKey:#"name"]];
];
NSLog(#"%#" ,name);
Please help me this to get student names
You are checking "name" key in "data" key, but in fact it is present in "Student" key.
Parse to Student object and using for loop get one by one "name" key value.
Use this site http://www.json4swift.com/ to create Model.(Just you have to Put JSON response here).
Var dataModelArray = [Your_Model_Type]()
if let data = data[“student”] as? [String: AnyObject] {
dataModelArray = Your_Model_type.modelsFromDictionaryArray(array: data)
}
//And you will have array of data in your dataModelArray
//Example you can access like this
dataModelArray[0].name

Reorganize dictionary order by values?

I have an app that receives an Json file from my webserver and I convert to NSDictionary as you can see below:
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]
The structure of my dictionary is as follows:
[0] => { "name" = "josh", meters = "8" }
[1] => { "name" = "lina", meters = "10" }
[2] => { "name" = "pall", meters = "21" }
You can see that data is already organized by the key meters, unfortunately my webserver not give the possibility to maintain an open connection, in this case, the new records will come through the APNS (push notification)
Assuming that comes the following record by notification:
{"name" = "oli", meters = "12"}
I insert it in my dictionary, but once that's done, how can I rearrange my array and order by meters?
There's no order inherent in the dictionary. That you see an ordering in the initial set is accidental.
Arrays have ordering, and you can get an array from a dictionary by sending it allKeys or allValues.
Using this fact to organize the dictionary, you might try something like this:
NSArray *orderedPairs = [#[] mutableCopy];
for (id key in [someDictionary allKeys]) {
[orderedPairs addObject:#[key, someDictionary[key]]];
}
[orderedPairs sortUsingComparator:^NSComparisonResult(NSArray *a, NSArray *b) {
// return [a[0] compare:b[0]]; // to sort by key
return [a[1] compare:b[1]]; // to sort by value
}];
Note that this will result in an array -- not a dictionary -- but one that is ordered.
Dictionary doesn't have order. it's simply key-value pair. you can fetch value for particular key so doesn't require sorting or ordering like array.

Combining several JSON objects into one

I need to put an array of JSON objects into a new JSON object.
{“megaObject”:[
{ “key”:8,
“key2”:”val”
},
{ “key”:5,
“key2”:”val”
},
{ “key”:6,
“key2”:”val”
}
]
}
I have created the array like this:
NSArray *myArray = #[NSData json1, NSData json2, NSData json3];
Is this the correct way to make a JSON array and if so, how can I put it as a value to key `megaObject.'
I'm new to iOS development so any help is great.
If you represent the JSON object as a NSDictionary, you can simply use the methods of this. I.e.
NSDictionary *jsonDict1;
NSDictionary *jsonDict2;
NSDictionary *jsonDict3;
NSArray *resultAry = #[jsonDict1, jsonDict2, jsonDict3];
NSDictionary *resultDict = #{#"megaObject" : resultAry};
and from here on convert to NSData or anything else you need ;) First understand what classes you are working with and then look at their methods in the API. Investigate more and concentrate your questions on things that you couldn't solve after at least 2 hours investigation ;)
UPDATE
taking a look at your structure...
{"megaObject": // <-- NSDictionary "resultDict" with the key "megaObject" and NSArray "resultAry" with 3 NSDictionaries as value.
[
{ // NSDictionary "jsonDict1" with 2 entries.
“key”:8,
“key2”:”val”
},
{ “key”:5, // and so on
“key2”:”val”
},
{ “key”:6,
“key2”:”val”
}
]
}
I would use NSJSONSerialization, from the documentation:
You use the NSJSONSerialization class to convert JSON to Foundation objects and convert Foundation objects to JSON.
Not sure what you want to reach as result, but this example can help you undersand how to assign an array as value into a NSDictionary as key.
NSDictionary *NEWjSON= [[NSDictionary alloc]init];
NSArray *myArray = #[
#{
#"key" : #"8",
#"key2" : #"val",
},
#{ #"key" : #"5",
#"key2":#"val",
},
#{ #"key":#"6",
#"key2":#"val"
}
];
[NEWjSON setValue:myArray forKey:#"megaObject"];

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

Keeping the order of NSDictionary keys when converted to NSData with [NSJSONSerialization dataWithJSONObject:]

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"
// }

Resources