I am trying to Parse JSON that looks like this:
food = {
"food_id" = 4823;
servings = {
serving = (
{
calcium = 9;
calories = 221;
carbohydrate = "16.20";
cholesterol = 31;
I can successfully retrieve the array at the [food][servings][serving] level, which I confirm via a log statement has the appropriate class, __NSCFArray, but I run into a problem when iterating through that array and trying to do useful things with the contained information:
for (id foodId in resultsPerServing) {
NSLog(#"hree is a result %#", foodId);
foodObjectClass *foodObject = [foodObjectClass new];
NSDictionary *foodIdDictionary = (NSDictionary *)foodId;
if ([foodIdDictionary respondsToSelector:#selector(allKeys)]) {
[foodObject getDetailsFromResponseObject:foodIdDictionary];
} else {
unsigned int mc = 0;
Method * mlist = class_copyMethodList(object_getClass(foodIdDictionary), &mc);
NSLog(#"%d methods", mc);
for(int i=0;i<mc;i++)
NSLog(#"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));
[NSException raise:#"DIDN'T GET A DICTIONARY" format:#"here is the object %# which has class %#", resultsPerServing, [responseObject class]];
}
}
This causes the NSException to be raised without fail although in the NSException the output from printing the object looks like a dictionary. Additionally, when the exception prints out the class of the object which does not respond to allKeys, that object has class __NSCFDictionary. What gives? Why does this dictionary not have an allKeys method and how can I get a functional dictionary to work with?
Even more puzzling is that the runtime code below (copied from an SO post for which I have lost the link) indicates that the dictionary has 0 methods. Why does this object have no methods? How can I get an object that does have methods?
make a check to confirm that it as NSDictionary first?
if ([foodId isKindOfClass:[NSDictionary class]] ) {
foodIdDictionary = (NSDictionary *)foodId;
[foodObject getDetailsFromResponseObject:foodIdDictionary];
}
Related
I know there's a lot of questions like this around, but I think my situation's a tad different.
int i = 0;
while (_data[#"VerticalState%i", i] != nil) {
// do things
i++;
}
For example, one 'level' that has 3 VerticalState properties will be implemented as such: VerticalState0, VerticalState1, VerticalState2.
I want to read in those values using that while loop condition above, and it should stop when i = 3. How can I make the idea of that code above work (with some other configuration obviously). FYI, _data is an NSDictionary* instance variable, already loaded with the plist information.
You appear to want to create a dictionary key from a string format. You need to use NSString stringWithFormat:.
while (_data[[NSString stringWithFormat:#"VerticalState%i", i]] != nil) {
Though it would be better to write the loop like this:
int i = 0;
while (1) {
NSString *key = [NSString stringWithFormat:#"VerticalState%i", i];
id value = _dict[key];
if (value) {
// do things
i++;
} else {
break;
}
}
I'm using the Edmunds API to return a JSON string of vehicle makes for a certain year.
The resulting NSDictionary looks like this:
makes = (
{
id = 200002038;
models = (
{ // not relevant
}
);
name = Acura;
niceName = acura;
},
{
id = 200001769;
models = (
{ // not relevant
}
);
name = "Aston Martin";
niceName = "aston-martin";
},
There are a lot more values in this dictionary...how can I loop through through the dictionary to retrieve each of the 'name' values?
I like valueForKeyPath because you can do so much with it and it's a one line solution. Tested this and it works in my dev setup. If you know your data is in a predictable format, then you can do amazing things with valueForKeyPath.
NSArray *makeNames = [makes valueForKeyPath:#"name"];
Great info on valueForKeyPath http://nshipster.com/kvc-collection-operators/
NSMutableArray *makeNames = [NSMutableArray new];
for (NSDictionary *make in makes) {
NSLog(#"Make name: %#", make[#"name"]);
[makeNames addObject:make];
}
NSLog(#"Makes array: %#", makeNames);
This the line i have using to convert the object to integer values,Inside For Loop I have Placed This code
NSInteger tag=[[arrFullSubCategory valueForKey:#"category"] integerValue];
Inside arrFullSubCategory:
(
{
category = 35;
image = "images/Hatchback.jpg";
name = Hatchback;
parent = 20;
},
{
category = 36;
image = "images/Sedan.jpg";
name = Sedan;
parent = 20;
},
{
category = 37;
image = "images/SUV.jpg";
name = SUV;
parent = 20;
}
)
Exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI integerValue]: unrecognized selector sent to instance 0x7ff4ba58f930'
arrFullSubCategory is an array and you should reach it's elements first. Than you will have NSDictionary objects. After that you can access your category element. So I think your code should be like that:
for (NSInteger i = 0; i < arrFullSubCategory.count; ++i) {
NSInteger tag=[[[arrFullSubCategory objectAtIndex:i] valueForKey:#"category"] integerValue];
}
Explanation of the error:
The error means you have an array, and arrays don't respond to integerValue.
Your variable arrFullSubCategory references an array (of 3 elements), and each element is a dictionary. If you call valueForKey: on an array of dictionaries then the key lookup is performed for each dictionary and an array is constructed for the results. In your case the result (using literal syntax) is the array:
#[ #35, #36, #37 ]
Whether this array is directly useful to you, or whether you should access the array one element at a time - using a loop or method which calls a block per element, etc. - will depend on what your goal is.
HTH
Try this code inside for loop I hope this help you
NSInteger tag=[[[arrFullSubCategory objectAtIndex:i] valueForKey:#"category"] integerValue];
you have array of dictionary, So you use it given below code
[[[arrFullSubCategory objectAtIndex:] objectForKey:#"category"] integerValue]
I am trying to correctly target the elements within the Json Output and I am getting closer but I presume there is a easy and obvious way I am missing.
My Json looks like this with a upper level event.
JSON SNIPPET UPDATED
chat = (
(
{
Key = senderId;
Value = {
Type = 0;
Value = "eu-west-1:91afbc3f-890a-4160-8903-688bf0e9efe8";
};
},
{
Key = chatId;
Value = {
Type = 0;
Value = "eu-west-1:be6457ce-bac1-412d-9307-e375e52e22ff";
};
},
{
Key = timestamp;
Value = {
Type = 1;
Value = 1430431197;
};
},
//Continued
I am targeting this level using
NSArray *chat = array[#"chat"];
for ( NSDictionary *theCourse in chat )
{
NSLog(#"---- %#", theCourse);
// I tried the following to target the values
//NSLog(#"chatId: %#", [theCourse valueForKey:#"Key"]);
//NSLog(#"timestamp: %#", theCourse[#"senderId"] );
}
}
I need to parse the value data for each key which if I was using an array would do like [theCourse valueForKey:#"Key"] but I think I may not be going deep enough?
As you would expect, [theCourse valueForKey:#"Key"] gives me the Key values but I need the associate values of those keys.
You can create an easier dictionary:
NSArray *chat = array[#"chat"][0];
NSMutableDictionary* newDict = [NSMutableDictionary dictionary];
for (NSDictionary* d in chat)
[newDict setValue:d[#"Value"][#"Value"] forKey:d[#"Key"]];
Now you can use the newDict.
NSLog(#"chatId: %#", [newDict valueForKey:#"chatId"]);
I'm trying to get the nearby places using the foursquare api.
Here's the json data that is returned from
NSDictionary *results = [jsonString JSONValue];
NSLog(#"%#", results);
(
{
code = 200;
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
errorType = deprecated;
},
{
groups = (
{
items = (
{
categories = (
{
icon = "https://foursquare.com/img/categories/parks_outdoors/default.png";
id = 4bf58dd8d48988d163941735;
name = Park;
parents = (
"Great Outdoors"
);
pluralName = Parks;
primary = 1;
shortName = Park;
}
);
Then I try to get the list of the groups in an array with
NSArray *groups = [ (NSDictionary *)results objectForKey:#"groups"];
This returns the following error
2011-11-05 11:42:12.907 XperienzApp[1972:207] No of results returned: 0 Results : (null)
2011-11-05 11:42:13.225 XperienzApp[1972:207] -JSONValue failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=3 \"Unrecognised leading character\" UserInfo=0x5849cd0 {NSLocalizedDescription=Unrecognised leading character}"
)
2011-11-05 11:42:13.225 XperienzApp[1972:207] No of results returned: 0 Results : (null)
How should I parse this?
Edit:
I tried the suggested technique, this gives me an array
id groups = [[(NSDictionary *)results objectForKey:#"response"] objectForKey:#"groups"];
if ([results count] > 1){
NSLog(#"groups class %#\ngroups %# %d", groups, [groups class], [groups count]);
The log output is of the form:
{
categories = (
{
icon = "https://foursquare.com/img/categories/nightlife/danceparty.png";
id = 4bf58dd8d48988d11f941735;
name = Nightclub;
parents = (
"Nightlife Spots"
);
pluralName = Nightclubs;
primary = 1;
shortName = Nightclub;
}
);
contact = {
};
hereNow = {
count = 0;
};
id = 4eb33ba561af0dda8f673c1b;
location = {
address = "144 Willow St 4R";
city = Brooklyn;
crossStreet = Pierrepont;
distance = 462;
lat = "40.696864";
lng = "-73.996409";
postalCode = 11201;
state = NY;
};
name = "Entertainment 720, Ltd.";
stats = {
checkinsCount = 3;
tipCount = 0;
usersCount = 1;
};
verified = 0;
}
);
name = Nearby;
type = nearby;
}
)
groups __NSArrayM 1
This is again not json and is hard to parse, how do I get the output in json.
I'm the iPhone lead at foursquare. I'll try to take a stab at what's going on here.
First of all, I highly recommend you use JSONKit for your parser. It's lightweight and insanely fast: https://github.com/johnezang/JSONKit
It appears that you are parsing the JSON properly and getting the dictionary properly. Then you are logging the parsed object, not the original JSON. The output you are seeing is how Objective-C chooses to serialize the parsed dictionary to text. It is definitely not JSON. Using JSONKit, you could send the JSONString selector to your parsed result and convert it back to JSON and log that.
If you could provide some details on the problem you are trying to solve, I might be able to help you out more. And as Maudicus said, please pay attention to the error you are getting back. You don't want your app to break when we make the change to the API.
If the output below NSLog(#"%#", results); is your log statement. It appears your results variable is an array of dictionary objects.
Try to log the class of results to verify that NSLog(#"%#", [results class]);
If it is an array your groups object is the second object.
if ([results count] > 1)
id groups = [results objectAtIndex:1];
NSLog(#"groups class %#\ngroups %#", [groups class], groups);
Keep doing this until you understand the format of your data
Also the line
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
should be cause for concern. Check the documentation on foursquare for the current way of getting groups.