Search code examples
jsonios7nsjsonserialization

iOS7 NSJSONSerialization - how to drill down multiple levels


I'm trying to read data from weather underground via their JSON API. I'm able to read conditions data which looks like this:

weatherReturn = { "current_observation" = { UV = 1; "dewpoint_c" = 2; "dewpoint_f" = 35; "dewpoint_string" = "35 F (2 C)"; "display_location" = { city = Chicago; country = US; ...

Now, I'm trying to read JSON data from the forecast data which looks like this:

forecast = { simpleforecast = { forecastday = ( { avehumidity = 45; avewind = { degrees = 141; dir = SE; kph = 14; mph = 9; }; conditions = Clear; date = { ampm = PM; day = 19;

and my code is returning null for the attributes I'm trying to pick up.

Since forecast has more layers to the JSON data than conditions, I'm trying a new method which is returning the nulls. Also, I noticed there is a left paren after forecast_day for the forecast data.

The code I'm trying is below:

urlNSString = [NSString stringWithFormat:@"http://api.wunderground.com/api/%@/forecast/q/Chicago.json",
             kWeatherAPIKey];
NSURL *url          = [NSURL URLWithString:urlNSString];

NSData *weatherCall = [NSData dataWithContentsOfURL:url];    

id weatherReturn = [NSJSONSerialization weatherCall options:0 error:&error];

NSMutableDictionary *response = [[[weatherReturn valueForKey:@"forecast"] objectAtIndex:0]mutableCopy];
NSString *parma = [response valueForKey:@"avehumidity"];
NSString *parmb = [response valueForKey:@"pretty"];
NSString *parmc = [response valueForKey:@"ampm"];

NSLog(@"parms are %@%@%@",parma,parmb,parmc);

When I run with this code I get this error on the NSMutableDictionary statement: [__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x9847fa0 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x9847fa0'

libc++abi.dylib: terminating with uncaught exception of type NSException


Solution

  • The response is not a simple NSDictionary object. It is a dictionary of arrays and dictionaries that may contain other arrays and dictionaries etc.

    You have to know what is the structure of your response (for example by NSLogging it).
    Try: NSLog(@"%@", weatherReturn);


    {...} means a NSDictionary object.
    (...) means a NSArray object

    I changed your code to prove that the params you're looking for are not nil.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
    
        NSString *urlNSString = [NSString stringWithFormat:@"http://api.wunderground.com/api/%@/forecast/q/Chicago.json",kWeatherAPIKey];
        NSURL *url          = [NSURL URLWithString:urlNSString];
    
        NSData *weatherCall = [NSData dataWithContentsOfURL:url];
    
        NSError *error;
        id weatherReturn = [NSJSONSerialization JSONObjectWithData:weatherCall options:0 error:&error];
    
        NSLog(@"%@", weatherReturn);
    
        id forecast = [weatherReturn valueForKey:@"forecast"];
        id simpleforecast = [forecast valueForKey:@"simpleforecast"];
        id forecastday = [simpleforecast valueForKey:@"forecastday"];
    
        id firstPartOfDailyForecast = [forecastday firstObject];
    
        id avehumidity = [firstPartOfDailyForecast valueForKey:@"avehumidity"];
    
        id date = [firstPartOfDailyForecast valueForKey:@"date"];
    
        id pretty = [date valueForKey:@"pretty"];
        id ampm = [date valueForKey:@"ampm"];
    
    
        NSLog(@"Ave:%@\nPretty:%@\nAM/PM:%@", avehumidity, pretty, ampm);
    }
    

    IMPORTANT
    I'm not calling valueForKey: method on weatherReturn all the time, but i'm getting deeper and deeper inside the response structure.


    This is how the structure looks like for param with key "ampm"

    --NSDictionary (response)
    ----NSDictionary for key forecast
    -------NSDictionary for key simpleforecast
    ---------NSArray for key forecastday
    -----------NSDictionary as first array object
    -------------NSDictionary for key date
    ---------------NSString for key ampm
    

    EDIT:

    I just found this tool, you might find it helpful :)

    JSON VIEWER

    How to use it:

    1. Place your request (but change API KEY :)) request into a browser
      http://api.wunderground.com/api/YOUR_API_KEY/forecast/q/Chicago.json
    2. Copy the API response to the tool's 'Text' page.
    3. Go to 'Viewer' page and analize the response.