Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Thomas Nilsen
Thomas Nilsen
14,957 Points

Retrieve latitude and longitude from parsed JSON file

I'm trying to implement MKMapView and CLLocationManager, to find my current position and display annotations that I get from a JSON response on the map.

here is the code which is supposed to display the annotations:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.mapView = [[MKMapView alloc] init];
    self.mapView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
    self.mapView.showsUserLocation = YES;
    self.mapView.delegate = self;

    [self.view addSubview:self.mapView];

    MainViewController *mainVC = [[MainViewController alloc] init];

    for (NSDictionary *location in mainVC.venues) {
        CLLocationCoordinate2D annotationCoordinate = CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]);
        Annotations *annotation = [[Annotations alloc] init];
        annotation.coordinate = annotationCoordinate;

        [self.mapView addAnnotation:annotation];
    }
}

I'm positive this line is the problem:

CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]);

But the JSON format got me confused. What is the correct way the get the latitude and longitude when the JSON looks like this: http://imgur.com/XHBUDwY

Cheers!

1 Answer

First problem is that when you are iterating through your venues, I can only assume that your location is not yet at the depth of location in the tree. This is what you need to do instead to access location:

for ( NSDictionary * venue in mainVC.venues ) {
  NSDictionary * location = venue[@"location"];
  // ...
}

Also, depending on your parser, your lat/lon values may have been parsed into NSString instead of NSNumber. You should check this by setting a breakpoint inside your loop and inspect those values.

If they are indeed NSStrings, you need to instantiate a simple NSNumberFormatter and use its numberFromString method.

Thomas Nilsen
Thomas Nilsen
14,957 Points

I think you misunderstand a little bit, or maybe my question was confusing. I know JSON are parsed at string (most of the time). I added a image-link so you can see what the response I get back looks like. What I'm struggling with, is how to retrieve the lat and lng. When I look at the JSON file it goes something like "response" - "venues" - "location" - "lat" and lng". Meaning my line of code:

CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]);

Won't work, but I don't know what to write instead.

First, try the code I gave you.

Thomas Nilsen
Thomas Nilsen
14,957 Points

Tried this:

for (NSDictionary *venue in mainVC.venues) {
        NSDictionary *location = venue[@"location"];
        CLLocationCoordinate2D annotationCoordinate = CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]);
        Annotations *annotation = [[Annotations alloc] init];
        annotation.coordinate = annotationCoordinate;

        [self.mapView addAnnotation:annotation];
    }

Ended up with with loong error:

2014-01-20 00:24:32.390 testApp[49745:70b] -[NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x9f96f50 2014-01-20 00:24:32.393 testApp[49745:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x9f96f50'

OK, that means your parser has unfolded the internal structure of the JSON and has essentially changed the hierarchy. To know the hierarchy, NSLog one of your dictionaries within your loop:

   for (NSDictionary * venue in mainVC.venues) {
       NSLog(@"%@", venue);
       abort(); // abort the program until we figure out what's going on.
   }
Thomas Nilsen
Thomas Nilsen
14,957 Points

All the console gave me was:

2014-01-20 00:35:41.490 testApp[49905:70b] confident

But when I logged out the content of the loop in my main ViewController where I parse the JSON file i got:

2014-01-20 00:40:06.723 testApp[49989:70b] confident 2014-01-20 00:40:06.725 testApp[49989:70b] neighborhoods 2014-01-20 00:40:06.725 testApp[49989:70b] venues 2014-01-20 00:40:06.725 testApp[49989:70b] geocode

:)

Now I know what's going on. What you threw into mainVC.venues is actually the full response dictionary. Thus when you enumerate through it, it yields the keys instead. First, to fix the semantics, change the name of that property to responses. Next, your enumeration should look something like the following:

for ( NSDictionary * venue in mainVC.responses[@"venues"] ) {
    NSDictionary * location = venue[@"location"];
    //...
    // My guess is the coordinates are NSString. If that's the case, create an NSNumberFormatter object outside the loop
    // and use its numberFromString method
}
Thomas Nilsen
Thomas Nilsen
14,957 Points

The is probably just me being tired but, I don't have a property in mainVC called responses? In MainViewController.m i have this line of code:

    self.venues = [dataDictionary objectForKey:@"response"];

and that's what I loop through in my mapViewController, so isn't

Objective-C
for ( NSDictionary * venue in mainVC.venues ) {
}

enough? Also I don't know If you saw it in my original post: heres is part of the JSON I'm working with: http://imgur.com/XHBUDwY

Be assured that I have read your original post in depth and have quite thorough understanding of what the structure of the JSON response. But also keep in mind that your parser is not exactly doing what you think it is doing, i.e. just looking at the HTTP JSON response without knowing the behavior of your parser is pointless.

To make it easier for you, just make the following two changes:

In your MainViewController:

    self.venues = dataDictionary[@"response"][@"venues"]; // This corrects a bug in your parser

Outside, in the loop you had:

    for (NSDictionary * venue in mainVC.venues) {
        NSDictionary * location = venue[@"location"];
        // ...
    }
Thomas Nilsen
Thomas Nilsen
14,957 Points

Thank you so much! So simple mistake, maybe because I'm tired. Either way, again, Thanks!