String to JSON Array unrecognized selector error - ios

I'm trying to parse some JSON to a NSArray but I'm getting the following error:
[__NSCFDictionary length]: unrecognized selector sent to instance 0x6d7a160
The area of code that's throwing this error is:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSError* error;
NSLog(responseString);
NSArray *jsonArray = [NSJSONSerialization
JSONObjectWithData:responseData
options:NSJSONReadingMutableContainers
error:&error];
parties2=jsonArray;
NSLog([parties2 objectAtIndex:0]); //Exception thrown
[tableView reloadData];
}
parties2 is previously defined as:
parties2=[NSArray arrayWithObjects:nil];
My ResponseString looks like
[{"Name":"party 1.1","GreekName":"FoA 1","GreekID":325,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":1000,"price":15.0},{"Name":"party 1.2","GreekName":"FoA 1","GreekID":325,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":300,"price":20.0},{"Name":"party 1.3","GreekName":"FoA 1","GreekID":325,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":5000,"price":25.0},{"Name":"party 2.1","GreekName":"FoA 2","GreekID":326,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":500,"price":25.0},{"Name":"party 2.2","GreekName":"FoA 2","GreekID":326,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":300,"price":30.0},{"Name":"party 3.1","GreekName":"FoA 3","GreekID":327,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":0,"price":50.0},{"Name":"party 5.1","GreekName":"FoA 5 ","GreekID":329,"schoolName":"FoA University","schoolID":10,"numberAttending":0,"maxNumberAttending":300,"price":15.75}]
This is my first venture with ObjC, I'm coming from a .Net C# background so chances are I'm missing a very simple thing.
Thanks :)

Your JSON parsing is correct. The error is being thrown because of a bad syntax in your NSLog() statement.
NSLog() takes an NSString as an argument, but your are trying to pass an NSDictionary instead (i.e. the first element of your NSArray), which is causing the error.
The solution to this is to use an NSString format string to convert the NSDictionary object to a string, like this:
NSLog(#"%#",[parties2 objectAtIndex:0]);

Related

Getting one value from JSON API in Objective-C

I'm trying to get one value from JSON. JSON is located in NSString and it looks like this:
{"coord":{"lon":-122.38,"lat":37.57},"weather":[{"id":300,"main":"Drizzle","description":"Lekka mżawka","icon":"09d"}],"base":"stations","main":{"temp":304.74,"pressure":1017,"humidity":35,"temp_min":300.15,"temp_max":307.59},"visibility":16093,"wind":{"speed":6.7,"deg":250},"clouds":{"all":75},"dt":1437346641,"sys":{"type":1,"id":478,"message":0.0615,"country":"US","sunrise":1437311022,"sunset":1437362859},"id":5357155,"name":"Hillsborough","cod":200}
I'm interested in getting "temp". How should I do that?
Assuming your JSON string was stored as a NSString named JSONString:
NSError *error;
NSDictionary *keys = [NSJSONSerialization JSONObjectWithData:[JSONString dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:&error];
NSLog(#"temp = %#", keys[#"main"][#"temp"]); // temp = 304.74
To get the main sub item in weather, which is an array with multiple items, you should point out its index to tell the selector which object in the array is the one you are looking for. In this case, it's 0:
NSLog(#"weather = %#", keys[#"weather"][0][#"main"]); // weather = Drizzle

NSJSONSerialization with an integer

I'm writing an iOS application that gets data from a web request. The request returns the following:
{"hash":"0369a5d5e65335309b2b1502dc96b5aba691b9451c83b9","error":0}
I get the data from the NSData* responseData object as follows:
NSDictionary* JSONdata = [NSJSONSerialization JSONObjectWithData:_responseData options:0 error:&error];
NSInteger responseError = (NSInteger)[JSONdata objectForKey:#"error"];
However, responseError is coming back uninitialized (filled with garbage values). I tried changing NSInteger to NSString* but that yields the following error
'NSInvalidArgumentException', reason: '-[__NSCFNumber length]: unrecognized selector sent to instance 0x9d02220'
Any ideas?
You need to use an NSNumber. Primitive values will not work for as iOS parses the data in NSObjects: NSArray, NSDictionary, NSNumber, NSString, and NSNull.
Try this: NSNumber *responseError = [JSONdata objectForKey:#"error"];
Then to convert to an NSInteger you can do this:
NSInteger responseInt = [responseError integerValue]; this will return an integer value.
Also for future reference, an NSDictionary cannot contain any primitive values.

JSON not working as expected on iOS

I'm currently trying to parse this JSON
[{"id":"1","dish_name":"Pasta & ketchup","category":"main","rating":"5","rating_count":null,"author":"Me","ingredients":"Pasta\nKetchup\nWater","description":"Very good for students\nCheap too!","picture":null,"protein":"7","fat":"11","carbs":"12","calories":"244","developer_lock":"1"},{"id":"2","dish_name":"Pasta & Kødsovs","category":"main","rating":"5","rating_count":null,"author":"Me","ingredients":"Pasta\nKødsovs\nWater","description":"Very good for students\nCheap too!","picture":null,"protein":"7","fat":"11","carbs":"12","calories":"244","developer_lock":"1"}]
But it fails and crashes with this code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSError *error = NULL;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
recipes = [[NSArray alloc] initWithArray:[json objectForKey:#"dish_name"]];
[uit reloadData];
}
Do someone have any clue, why it crashes with error -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x8077240
?
Thanks in advance.
The error message beginning with [__NSCFArray objectForKey:] means that you have an NSArray (the root object of the JSON is an array - notice the opening and closing square brackets) and you're trying to treat it as a dictionary. All in all,
recipes = [[NSArray alloc] initWithObject:[json objectForKey:#"dish_name"]];
should be
recipes = [[NSArray alloc] initWithObject:[[json objectAtIndex:0] objectForKey:#"dish_name"]];
Note that there are two objects in the array, so you might want to use [json objectAtIndex:1] as well.
Edit: if you have a dynamic number of recipes, you can do this:
recipes = [[NSMutableArray alloc] init];
for (NSDictionary *dict in json) {
[recipes addObject:[dict objectForKey:#"dish_name"]];
}
If your json NSDictionary were a real & valid NSDictionary object, your call to this:
[json objectForKey:#"dish_name"]
should return exactly this:
"Pasta & ketchup"
Which is definitely not an array. It's a NSString object.
Which would be why the call to "initWithArray" is bombing.

Cannot access NSDictionary

I created a JSON using a PHP script.
I am reading the JSON and can see that the data has been correctly read.
However, when it comes to access the objects I get unrecognized selector sent to instance...
Cannot seem to find why that is after too many hours. Any help would be great!
My code looks like that:
NSDictionary *json = [[NSDictionary alloc] init];
json = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
NSLog(#"raw json = %#,%#",json,error);
NSMutableArray *name = [[NSMutableArray alloc] init];
[name addObjectsFromArray: [json objectForKey:#"name"]];
The code crashes when reaching the last line above.
The output like this:
raw json = (
{
category = vacancies;
link = "http://blablabla.com";
name = "name 111111";
tagline = "tagline 111111";
},
{
category = vacancies;
link = "http://blobloblo.com";
name = "name 222222222";
tagline = "tagline 222222222";
}
),(null)
2012-06-23 21:46:57.539 Wind expert[4302:15203] -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0xdcfb970
HELP !!!
json is an array from what you've shown, not a dictionary. I can tell this because of the parentheses surrounding the whole of the log output for json. Inside the array are dictionaries, which I can tell by the fact that they are surrounded by braces.
So, it looks like you want something like this:
NSError *error = nil;
NSArray *json = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
NSLog(#"raw json = %#,%#",json,error);
NSMutableArray *name = [[NSMutableArray alloc] init];
for (NSDictionary *obj in json) {
[name addObject:[obj objectForKey:#"name"]];
}
As an aside you will notice I have removed the unnecessary initialisation of json to an object before overwriting in the next line with JSONObjectWithData:options:error:. In an ARC world it wouldn't be a leak but it's still completely unnecessary to allocate an object just to get rid of it again a moment later. Also I added in the NSError *error = nil; line since that was not there and was obviously necessary to compile.
The problem appears to be that the root level of your JSON is an array, not a dictionary (note the parenthesis instead of curly brace as the first character in the logged output). Arrays do not have objectForKey selector. Perhaps you intend to take objectAtIndex:0 first, or else iterate over all the the items?
As an aside, the first line of your code makes a completely wasted initialization of an NSDictionary. It is simply overwritten and deallocated on the very next line.

Weird crash while accessing array objects at a given index in IOS

We have the following method where we are trying to access an array object at a given index. The array is resultArr. When we do a resultArr count it gives us a result of 13. So we know that the array is not null but when we try to do objectAtIndex it crashes with the error.
Function:
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray *keys = [json allKeys];
NSLog(#"keys: %#",keys);
NSArray* htmlAttributions = [json objectForKey:#"html_attributions"]; //2
NSArray* resultArr = (NSArray *)[json objectForKey:#"result"]; //2
NSArray* statusArr = [json objectForKey:#"status"]; //2
NSLog(#"htmlAttributions: %#",htmlAttributions);
NSLog(#"result: %#", resultArr); //3
NSLog(#"status: %#", statusArr); //3
NSLog(#"resultCount: %d",[resultArr count]);
[resultArr objectAtIndex:0];
}
Error:
2012-04-01 22:31:52.757 jsonParsing[5020:f803] resultCount: 13 2012-04-01 22:31:52.759 jsonParsing[5020:f803] -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6d2f900 2012-04-01 22:31:52.760 jsonParsing[5020:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6d2f900'
*** First throw call stack:
Thank you.
The error message is fairly descriptive. One of the objects that your code expects to be an NSArray is actually an NSDictionary. You cannot access fields inside of an NSDictionary by using NSArray methods (and casting from NSDictionary* to NSArray* will not convert an NSDictionary into an NSArray).
This would mean that inside of the JSON, one of your elements was serialized as an object/associative array instead of as a plain array. You can easily determine which one by looking at your JSON data as text, and finding the item that uses { and } instead of [ and ].
You are saying
NSArray* resultArr = (NSArray *)[json objectForKey:#"result"]; //2
But that does not make this object ([json objectForKey:#"result"]) an NSArray. It is an NSDictionary, and sending it a message that NSDictionary does not respond to (objectAtIndex:) causes a crash.
You were able to send it the count message without crashing because NSDictionary does happen to respond to the count message. But your preconception that this is an array is still mistaken.
You cannot cast an NSDictionary* to an NSArray* as you tried to do with this line: NSArray* resultArr = (NSArray *)[json objectForKey:#"result"];, then call -objectAtIndex.

Resources