Question

I was using google API to obtain the geo co-ordinates. The code I have been using till now is as below

-(CLLocationCoordinate2D) getLocationFromAddressString:(NSString*) addressStr {

NSString *urlStr = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv",
                    [addressStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlStr] encoding:NSStringEncodingConversionAllowLossy error:nil];
NSArray *items = [locationStr componentsSeparatedByString:@","];
double latitude = 0.0;
double longitude = 0.0;

//NSLog(@"items array %@", items);

if([items count] >= 4 && [[items objectAtIndex:0] isEqualToString:@"200"]) {
    latitude = [[items objectAtIndex:2] doubleValue];
    longitude = [[items objectAtIndex:3] doubleValue];
}
else {
    //NSLog(@"Address, %@ not found: Error %@",addressStr, [items objectAtIndex:0]);
}

CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
return location;
}

I wish to use CLGeocoder in the place of google API to obtain the location co-ordinates from an address string.

I have been working with CLGeocoder seen from examples online. I find it a bit hard task working with the CLGeocoder. I tried to use the CLGeocoder without changing much from my previous code, so that I don't have to make big changes in the existing code.

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) {
    self.placemarksArray = placemarks;
    CLPlacemark *placeInfo = [placemarks objectAtIndex:0];
    NSString *latitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.latitude ];
    NSString *longitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.longitude ];
    NSLog(@"latitudeString %@", latitudeString);
    NSLog(@"longitudeString %@", longitudeString);

    _latitudes = placeInfo.location.coordinate.latitude;
    _longitudes = placeInfo.location.coordinate.longitude;
}];
location.latitude = _latitudes;
location.longitude = _longitudes;
return location;

But what happens is that, the map view gets loaded before the block is executed. The exact value of the location is not returned in this case.

My question is :

  1. Is it possible to use CLGeocoder, without making much changes to my previous code. Or should I need to change the whole structure.
  2. From the 2nd block of code I have tried, what I am I doing wrong and how may I correct it?

Edit: The above method is called from viewDidLoad

CLLocationCoordinate2D mapCenter = [self getLocationFromAddressString:fullAddress];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
            [annotationPoint setCoordinate:mapCenter];
            [annotationPointsArray addObject:annotationPoint];
addAnnotation = [[[MyAddressAnnotation alloc] initWithCoordinate:mapCenter title:firstName SubTitle:lastName]autorelease];

 [mapView addAnnotation:addAnnotation];

This gets executed after getting the CLLocationCoordinate2D latitude and longitude values from getGeoLocation method.

Was it helpful?

Solution

CLGeocoder happens asynchronously (the fact that it's done in a block gives that away), and thus _latitudes and _longitudes are not set by the time the method, itself, returns. So, likely, yes, some slight restructuring of your code will be needed. It's hard for us to advise as we don't see the code that calls this routine. Bottom line, you have to refactor that code so that rather than returning the location, you have the completionHandler of geocodeAddressString invoke whatever you need done.

Looking at your revised code, it appears that your viewDidLoad is taking the location coordinates and creating an annotation. Just do that adding of the annotation inside the geocoded block.

Thus:

-(CLLocationCoordinate2D) geocodeAddressString:(NSString*)addressStr title:(NSString *)title subtitle:(NSString *)subtitle
{
    CLGeocoder *geocoder = [[[CLGeocoder alloc] init] autorelease];
    [geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) {
        self.placemarksArray = placemarks;
        CLPlacemark *placeInfo = [placemarks objectAtIndex:0];

        id<MKAnnotation> annotation = [[[MyAddressAnnotation alloc] initWithCoordinate:placeInfo.location.coordinate 
                                                                                 title:title
                                                                              SubTitle:subtitle] autorelease];

        [self.mapView addAnnotation:addAnnotation];
    }];
}

And then, viewDidLoad would call it as follows:

[self geocodeAddressString:fullAddress title:firstName subtitle:lastName]; 

OTHER TIPS

Nothing of magic, but you have to poke your mapview, inside your block:

self.mapView.centerCoordinate = placeInfo.location.coordinate //or equivalent of this, like latitudes and longitudes change

If you want to avoid the mapview being drawn twice, you need to intercept events of MKMapview (especially mapViewWillStartLoadingMap), implement them within your code, and put proper flags to avoid the map being drawn till the time reverse geocoding block hasn't been executed.

Try this answer.

Call method with some part of delay (i.e. 2 seconds).

[self performSelector:@selector(geoCodeUsingAddress:) withObject:userAddress afterDelay:2.0];

Calling GetCurrentLocation function

- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)addressStr
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) {
       self.placemarksArray = placemarks;
       CLPlacemark *placeInfo = [placemarks objectAtIndex:0];

       NSString *latitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.latitude ];
       NSString *longitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.longitude ];

       NSLog(@"latitudeString %@", latitudeString);
       NSLog(@"longitudeString %@", longitudeString);

       _latitudes = placeInfo.location.coordinate.latitude;
       _longitudes = placeInfo.location.coordinate.longitude;
    }];

    location.latitude = _latitudes;
    location.longitude = _longitudes;

    return location;
}

Hopefully, it will help you.

Thanks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top