Parsing JSON in Objective-C - objective-c

I am trying to parse the JSON at this URL:
http://maps.googleapis.com/maps/api/geocode/json?address=canada&sensor=false
in Objective-C. I'm trying to get the northeast latitude under "bounds", and this is the code I've written to try and do that (feed is an NSDictionary object):
NSArray *results = [feed objectForKey:#"results"];
NSDictionary *firstResult = [results objectAtIndex:0];
NSArray *geometry = [firstResult objectForKey:#"geometry"];
NSDictionary *firstGeo = [geometry objectAtIndex:0];
NSArray *bounds = [firstGeo objectForKey:#"bounds"];
NSDictionary *northeast = [bounds objectAtIndex:0];
NSString *neLat = [[NSString alloc] initWithString:[northeast objectForKey:#"lat"]];
Even though it compiles fine and the JSON data is valid, when I run it I get this error:
[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0xa672390
2012-02-24 01:32:06.321 Geo[570:11603] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0xa672390'
I don't know why this is happening, as I successfully got long_name before… any help is greatly appreciated :)
Thanks in advance!

The geometry and bounds are already dictionaries.
"geometry" : { // <-- a dictionary!
"bounds" : { // <-- also a dictionary!
"northeast" : {
"lat" : 83.1150610,
"lng" : -52.62040200000001
},
So you should write
NSDictionary *geometry = [firstResult objectForKey:#"geometry"];
NSDictionary *bounds = [geometry objectForKey:#"bounds"];
NSDictionary *northeast = [bounds objectForKey:#"northeast"];

Check the following statement.
NSArray *geometry = [firstResult objectForKey:#"geometry"];
It seems for the geometry, it does not return NSArray. It returns NSDictionary

Related

JSON ObjectiveC - Error

Receiving the following error. I believe it has to do with the NSDictionary in the results of JSON array. I.e. NSDictionary within an NSDictionary maybe?
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x7f9298554560'
This is the JSON service when called. This is printed directly out of XCode but it looks clean to me.
Printing description of self->metArray:
{
weatherObservation = {
ICAO = YBBN;
clouds = "few clouds";
cloudsCode = FEW;
countryCode = AU;
datetime = "2014-11-24 03:00:00";
dewPoint = 20;
elevation = 5;
hectoPascAltimeter = 1014;
humidity = 61;
lat = "-27.38333333333333";
lng = "153.1333333333333";
observation = "YBBN 240300Z 02019KT 9999 FEW029 SCT250 28/20 Q1014";
stationName = "Brisbane Airport M. O";
temperature = 28;
weatherCondition = "n/a";
windDirection = 20;
windSpeed = 19;
};
}
This is the code that invokes the JSON service.
-(void)getMetar{
// NSString *location = #"YBBN";
NSString * const metarUrl =#"http://api.geonames.org/weatherIcaoJSON?ICAO=YBBN&username=demo";
NSURL *url2 = [NSURL URLWithString:metarUrl];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
metArray = [NSJSONSerialization JSONObjectWithData:data2 options:kNilOptions error:nil];
//Create an NSDictionary for the weather data to be stored.
NSDictionary *metarJson = [NSJSONSerialization JSONObjectWithData:data2 options:kNilOptions error:nil];
//Loop through the JSON array
NSArray *currentMetarArray = metarJson[#"weatherObservation"];
//set up array and json call
metarArray = [[NSMutableArray alloc]init];
for (NSDictionary *metaritem in currentMetarArray)
{
//create our object
NSString *nClouds = [metaritem objectForKey:#"clouds"];
NSString *nObservation = [metaritem objectForKey:#"observation"];
//Add the object to our animal array
[metarArray addObject:[[metar alloc]initWithclouds:(nClouds) andobservation:nObservation]];
}
}
It looks okay to me but maybe that is because I have been looking at it for hours.
Any ideas?
NSArray *currentMetarArray = metarJson[#"weatherObservation"];
for (NSDictionary *metaritem in currentMetarArray)
These lines are wrong. currentMetarArray is a dictionary, not array, it contains string key & value, so you should access it like in following way-
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSDictionary *weatherObservation = [jsonDictionary objectForKey:#"weatherObservation"];
then to get nCloud, use like
NSString *nClouds = [weatherObservation objectForKey:#"clouds"];
I go to your URL and get this message {"status":{"message":"the daily limit of 30000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.","value":18}}
But you can try my code, it worked for me
NSString *strUrl = #"http://api.geonames.org/weatherIcaoJSON?ICAO=YBBN&username=demo";
NSURL *url = [NSURL URLWithString:strUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSDictionary *weatherObservation = [json objectForKey:#"status"];
for (id key in weatherObservation) {
id value = [weatherObservation objectForKey:key];
NSLog(#"key = %#, value = %#", key, value);
}
The error thrown is the best clue for how you can fix this.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x7f9298554560'
What this means is that you're thinking an object is a dictionary when in reality it isn't.
You can combat this using NSObject methods such as:
[myObject respondsToSelector:(#selector(objectForKey:))]; // will return a boolean value.
to see if the object will respond to the method you hope to send it
or
[myObject isKindOfClass:[NSDictionary class]]; // will return a boolean value.
to determine if the object is a NSDictionary.
What's likely happening, though, is that you have an error in expectation with the Deserialized JSON Data.
Happy bug hunting!

How to parse this JSON response into a key & value pairs array

there are a lot of questions like this and i'm experienced with json format too but i couldnt parse the response below(at the bottom):
I'm using NSJSONSerialization for parsing the response into NSDictionary but the it gives the error like below:
My code:
NSString *subURL= sharedDa.ip;
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://192.168.69.230/tsadmin.php?tssearch=%#", subURL]]];
NSError *error=nil;
NSDictionary* portsResult=[NSJSONSerialization JSONObjectWithData:data options:
NSJSONReadingMutableContainers error:&error];
NSDictionary * tempPorts;
NSString *k;
for(k in [portsResult allKeys]){
tempPorts = [portsResult objectForKey:k];
NSLog(#"Temporary ports: %#", tempPorts);
}
And the error code is below:
2012-09-28 18:47:37.508 BNTPRO ST Manager[2609:fb03] -[__NSArrayM allKeys]: unrecognized selector sent to instance 0x6b83ed0
2012-09-28 18:47:37.511 BNTPRO ST Manager[2609:fb03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM allKeys]: unrecognized selector sent to instance 0x6b83ed0'
*** First throw call stack:
(0x1568022 0x1b20cd6 0x1569cbd 0x14ceed0 0x14cecb2 0x57cd 0x28fa1e 0x28fd11 0x2a18fd 0x2a1aef 0x2a1dbb 0x2a285f 0x2a2e06 0x2a2a24 0x3e59 0x2595c5 0x2597fa 0xaee85d 0x153c936 0x153c3d7 0x149f790 0x149ed84 0x149ec9b 0x245a7d8 0x245a88a 0x1c8626 0x26d2 0x2645 0x1)
terminate called throwing an exception(lldb)
now my data snippet is: [{"k1":{"v":"0"}},{"k2":{"v":"0"}},{"k3":{"v":"0"}},{"k4":{"v":"0"}},{"k5":{"v":"0"}},{"k6":{"v":"0"}},{"k7":{"v":"1"}},{"k8":{"v":"0"}},{"k9":{"v":"1"}},{"k10":{"v":"0"}},{"k11":{"v":"1"}},{"k12":{"v":"0"}},{"k13":{"v":"1"}},{"k14":{"v":"0"}},{"k15":{"v":"0"}},{"k16":{"v":"0"}}]
but it still gives the same error.. even i decşare the iVar as NSDictionary why does it complain of nsmutable array??
The JSON you're parsing is an array, not an object. So the result of [NSJSONSerialization JSONObjectWithData...] is not an NSDictionary *, but an NSArray * instead.
For example, for the JSON data
[{"k1":{"v":"0"}}, {"k2":{"v":"0"}}]
You can use something similar to this code (don't have xcode right now to try to run it):
NSArray * arr = [NSJSONSerialization JSONObjectWithData:data options:...];
int i;
for (i = 0; i < [arr count]; i++) {
NSDictionary * dic = [arr objectAtIndex:i];
NSString * k;
for (k in [dic allKeys]) {
NSLog(#"Temporary ports: %#", [dic objectForKey:k]);
}
}

SIGABRT on NSDictionary objectAtIndex: unrecognized selector

I'm having a weird error here.
I have an array named __ImageData:
static NSArray *__ImageData = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:#"ImageData" ofType:#"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:path];
NSString *error; NSPropertyListFormat format;
_ImageData = [NSPropertyListSerialization propertyListFromData:plistData
mutabilityOption:NSPropertyListImmutable
format:&format
errorDescription:&error];
When I NSLog out the content of the array, I get this output:
2012-08-23 16:36:35.573 CAT[28814:c07] {
"Item 0" = {
height = 7121;
name = Map1;
width = 8556;
};
"Item 1" = {
height = 7121;
name = Map2;
width = 8556;
};
"Item 2" = {
height = 7121;
name = Map3;
width = 8556;
};
}
But when I NSLog out NSLog(#"%#", [__ImageData objectAtIndex:0]);, I get this exception:
2012-08-23 16:36:35.573 CAT[28814:c07] -[__NSCFDictionary objectAtIndex:]:
unrecognized selector sent to instance 0x719d0f0
2012-08-23 16:36:35.574 CAT[28814:c07] *** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]:
unrecognized selector sent to instance 0x719d0f0'
*** First throw call stack:
etc..
I have no idea how to reach an object in this array.. It seemes like the objectAtIndex cant find any indexes, not even index:0, even though there is data inside.. Anyone know how to get it?
I am using the PhotoScroller-template from Apple, using the CATiledLayer. I think the whole thing is kinda funky, but everybody says we should use this for large images. Anyone have an explanation or a better idea than CATiledLayer for huge images? (8556*7121px).
And why do I get Dictionary-error from the NSArray?
When doing NSDictionary *dict = [__ImageData objectAtIndex:0], I also get the same exception.
Stian.
_ImageData is not an array, it is a dictionary. To display the first element of the dictionary you could do something like:
NSLog(#"%#", [_ImageData objectForKey:#"Item 0"]);
I ran into this same issue using an JSON Array. My fix was to convert it to an NSDictionary like so:
[(NSDictionary *)json objectForKey:#"detail"];
Or you could do it like this:
NSDictionary *dict = (NSDictionary *)array;

Accessing JSON data inside an NSDictionary generated from NSJSONSerialization

Having some trouble accessing the JSON data in the following URL ( http://jamesstenson.com/portraits/?json=1 ), basically I want to access the "full" "url"'s underneath "attachments". My code at the moment is as follows:
NSError *e = nil;
NSData *jsonFeed = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://jamesstenson.com/portraits/?json=1"]];
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:jsonFeed options:NSJSONReadingMutableContainers error: &e];
if (!jsonData) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in [jsonData objectForKey:#"page"]) {
for(NSDictionary *attachment in [item objectForKey:#"images"]) {
NSLog(#"%#", attachment);
}
}
}
This keeps throwing up an error:
2011-12-21 10:13:39.362 JSON[3463:f803] -[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x6a7b500
2011-12-21 10:13:39.363 JSON[3463:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x6a7b500'
I am aware I am accessing the items wrongly, but cannot figure out how to achieve this. I've tried several solutions such as http://blogs.captechconsulting.com/blog/nathan-jones/getting-started-json-ios5 - but no luck. I am complete newbie to iOS development and have a little knowledge of JSON. Thanks for everyones help in advance.
The problem is in you for loop
for(NSDictionary *item in [jsonData objectForKey:#"page"])
You won't get NSDictionary in item, it will return you key of Dictionary, which would be NSString
Check this link for each loop in objective c for accessing NSMutable dictionary to know how to traverse through NSDictionay
Below is the modified code for your requirement, might help you
if (!jsonData) {
NSLog(#"Error parsing JSON: %#", e); } else {
NSArray *attachments = [[jsonData objectForKey:#"page"] objectForKey:#"attachments"];
for(NSDictionary *object in attachments) {
NSLog(#"%#", [object objectForKey:#"images"]);
NSLog(#"%#", [[[object objectForKey:#"images"] objectForKey:#"full"] objectForKey:#"url"]);
}
}

"Terminating app due to uncaught exception 'NSInvalidArgumentException'" error with stringByTrimmingCharactersInSet on iPhone

I am reading JSON data back from a server, and I am trying to parse a particular string that contains an HTML URL. The data is in an NSString called current_weatherIconUrl2. The console output from Xcode is below:
2010-07-06 17:17:46.628 WhatToDo[13437:20b] Current Condition: URL2:("http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png")
What I tried to do is use "stringByTrimmingCharactersInSet" to parse the '(', '"', and also the line feed and newlines, but I am instead getting the NSInvalidArgumentException:
2010-06-30 00:18:07.357 WhatToDo[7299:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFArray stringByTrimmingCharactersInSet:]: unrecognized selector sent to instance 0x3e84970'
Here is an extract of the data that is returned from the server (information I want to extract is bolded):
2010-07-06 17:17:46.627 WhatToDo[13437:20b] Results: {
data = {
"current_condition" = (
{
cloudcover = 75;
humidity = 42;
"observation_time" = "08:47 AM";
precipMM = "0.0";
pressure = 1003;
"temp_C" = 36;
"temp_F" = 97;
visibility = 10;
weatherCode = 113;
weatherDesc = (
{
value = Sunny;
}
);
**weatherIconUrl = (
{
value = "http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0001_sunny.png";
}
);**
winddir16Point = WSW;
winddirDegree = 250;
windspeedKmph = 31;
windspeedMiles = 19;
}
);
};
}
Here is the code that parses the data into NSString variables.
- (void) readWeather {
NSLog(#"readWeather started");
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
NSData *jsonObjectString;
NSString *completeString = [NSString stringWithFormat:
#"http://www.worldweatheronline.com/feed/weather.ashx?key=988ae47cc3062016100606&lat=25.04&lon=121.55&num_of_days=5&format=json", jsonObjectString];
NSLog(#"Weather URL: %#", completeString);
NSURL *urlForValidation = [NSURL URLWithString:completeString];
NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
[validationRequest setHTTPMethod:#"POST"];
NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];
[validationRequest release];
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
// Create a dictionary from the JSON string
NSDictionary *results = [jsonString JSONValue];
NSLog(#"Results: %#", results);
NSArray *data = [[results objectForKey:#"data"] objectForKey:#"current_condition"];
NSArray *data2 = [[results objectForKey:#"data"] objectForKey:#"weather"];
NSCharacterSet *skipSet = [NSCharacterSet characterSetWithCharactersInString:#"("];
for (NSArray *current_condition in data)
{
// Get title of the image
NSString *temp_C = [current_condition valueForKey:#"temp_C"];
NSString *current_weatherDesc = [current_condition valueForKey:#"weatherDesc"];
NSString *current_weatherIconUrl = [current_condition valueForKey:#"weatherIconUrl"];
NSString *current_weatherIconUrl2= [current_weatherIconUrl valueForKey:#"value"];
//Commented out because this will create an exception:
//NSString *current_weatherIconUrl3 = [current_weatherIconUrl2 stringByTrimmingCharactersInSet:skipSet];
//NSLog(#"Current Condition: URL2: %#", *(current_weatherIconUrl3);
//Commented out because this will create an exception:
//current_weatherIconUrl3 = [current_weatherIconUrl3 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
Can someone tell me what I am doing wrong or if there is a better method than using stringByTrimmingCharactersInSet?
The error you're getting actually describes what goes wrong:
2010-06-30 00:18:07.357 WhatToDo[7299:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSCFArray stringByTrimmingCharactersInSet:]: unrecognized selector sent to instance 0x3e84970'
You're trying to send an unrecognized selector (stringByTrimmingCharactersInSet:) to an instance of NSCFArray (NSArray).
Obviously, this selector only exists on NSString, so this won't work.
It appears that [current_weatherIconUrl valueForKey:#"value"] really is an NSArray, not an NSString.
Thanks for your help Douwe M. I was able to make some modifications, and now the code creates the variables I need. See below...
NSArray *weatherIconUrl2= [weatherIconUrl valueForKey:#"value"];
NSString *weatherIconUrl3 = [[weatherIconUrl2 valueForKey:#"description"] componentsJoinedByString:#""];
[imageArray addObject:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:weatherIconUrl3]]]];
-Todd
Your json response may not in a correct format.
So, please validate your JSON response on jsonlint