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
Related
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"
// }
I have been trying to get around this but so far without any success.
I know how to solve this using for loop but i want to learn it using NSPredicate
I have the following NSArray of NSDictionaries
[ { "content"="content1", "path"="/usr/name/..." },
{ "content"="acontent2", "path"="/usr/name/..." },
{ "content"="content3", "path"="/usr/name/..." },
{ "content"="content14", "path"="/usr/name/..." } ]
I want to return an array of all values of the "content" key for all items in the array. ie, the return should be
[ "content1", "content2", "content3", "content4" ]
How to do this?
Thanks
You can do it like that:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"content =[cd] %#", #"content1"];
NSArray * array = [YourArray filteredArrayUsingPredicate:pred];
This will filter your array to show all values where content = content1.
But this is for filtering the array but the output you want:
[ "content1", "content2", "content3", "content4" ]
It looks more like sorting.
Hope I explained you how NSPredictate work.
Just use valueForKey:
NSArray *contentItems = [array valueForKey:#"content"];
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
The returned array contains NSNull elements for each object that returns nil.
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!).
{"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.
I am currently trying to work with json and objective-c however having a bit of difficulty. The following is the json that is being returned
{
sethostname = (
{
msgs = "Updating Apache configuration\nUpdating cPanel license...Done. Update succeeded.\nBuilding global cache for cpanel...Done";
status = 1;
statusmsg = "Hostname Changed to: a.host.name.com";
warns = (
);
});
}
I am able to check that the response is coming back and the key is sethostname however no matter what I try I cannot get for example the value of status or statusmsg. Can anyone point me in the right location. The following is basic code I am using to check that sethostname is returned.
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&myError];
NSLog([res description]);
NSArray *arr;
arr = [res allKeys];
if ([arr containsObject:#"sethostname"])
{
NSLog(#"worked");
}
When in doubt, write down the structure of your JSON data. For example:
{
sethostname = (
{
msgs = "Updating Apache configuration\nUpdating cPanel license...Done. Update succeeded.\nBuilding global cache for cpanel...Done";
status = 1;
statusmsg = "Hostname Changed to: a.host.name.com";
warns = (
);
});
}
(which is in NeXTSTEP property list format, actually) means that you have a top-level dictionary. This top-level dictionary contains a key called sethostname whose value is an array. This array is comprised of dictionaries, each dictionary having a set of keys: msgs, status, statusmsg, warns. msgs has a string value, status has a number value, statusmsg has a string value,warns` has an array value:
dictionary (top-level)
sethostname (array of dictionaries)
dictionary (array element)
msgs (string)
status (number)
statusmsg (string)
warns (array)
??? (array element)
Having understood this structure, your code should look like:
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&myError];
if (!res) { // JSON parser failed }
// dictionary (top-level)
if (![res isKindOfClass:[NSDictionary class]]) {
// JSON parser hasn't returned a dictionary
}
// sethostname (array of dictionaries)
NSArray *setHostNames = [res objectForKey:#"sethostname"];
// dictionary (array element)
for (NSDictionary *setHostName in setHostNames) {
// status (number)
NSNumber *status = [setHostName objectForKey:#"status"];
// statusmsg (string)
NSString *statusmsg = [setHostName objectForKey:#"statusmsg"];
…
}
Why not use the simplest JSON method - [myString jsonValue];
It's part of this JSON framework for objective-c
I don't think if ([arr containsObject:#"sethostname"]) is going to work, because the results array is not going to contain that exact object. It might contain an object with the same content, but it won't be the SAME object.
As jtbandes wrote, you need to log the actually output. NSLog both res and arr and see what you have.