0

I'm trying to add city & state information to an MKAnnotation but the data is being cleared before I can add it to the annotation. Here is my current code (only showing the sections/parts of concern for simplicity):

in implementation:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation
{     
    CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
    [geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
    CLPlacemark *placemark = [placemarks objectAtIndex:0];
    [self setCity:[placemark locality] andState:[placemark administrativeArea]];
    }];

    NSLog(@"Location 1: %@, %@", city, state);

    MapPoint *mp = [[MapPoint alloc] initWithCoordinate:[newLocation coordinate]
                                                  title:[locationTitleField text]
                                                   date:[dateFormat stringFromDate:today]];

    [mapView addAnnotation:mp];
}

- (void)setCity:(NSString *)c andState:(NSString *)s
{
    [self setCity:c];
    [city retain];
    [self setState:s];
    [state retain];
    NSLog(@"Location 2: %@, %@", city, state);
}

in interface:

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate, MKMapViewDelegate>
{
    CLLocationManager *locationManager;
    IBOutlet MKMapView *mapView;
    NSString *city;
    NSString *state;
}

@property (strong, nonatomic) IBOutlet UIWindow *window;
@property (nonatomic, copy) NSString *city;
@property (nonatomic, copy) NSString *state;

- (void)setCity:(NSString *)c andState:(NSString *)s;

@end

Location 1 prints (null), (null) while Location 2 prints San Francisco, California. Why is the data being erased from these properties before I can use them in my annotation?

Much thanks...

Kevin_TA
  • 4,575
  • 13
  • 48
  • 77
  • Where do you set the MKAnnotation? – David V Dec 23 '11 at 02:19
  • I added some code showing where I am setting the MKAnnotation. The class MapPoint conforms to the MKAnnotation protocol. Don't worry about the date stuff. If I can get the city and state before I make the annotation, I will be adding that to the subtitle. – Kevin_TA Dec 23 '11 at 03:05
  • That explains the problem. See the updated section in my answer. – David V Dec 23 '11 at 03:15

1 Answers1

1

The reason Location 1 is null is that the reverse geocoder has not completed when it is run. Everything in your completionHandler will occur after the geocoder finishes. Your log statement for location 1 is not part of that completionHandler and is executed immediately after the call to reverse geocode. The end result is that the log call occurs before you call setCity:andState:.

Update

You need to set the annotation in the completionHandler block. The code which occurs in the block occurs later in sequence and time than the the rest of your locationManager:didUpdateToLocation:fromLocation: message implementation. You may wish to read about blocks from Apple's documentation or search the internet.

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation
{     
    CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
    [geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        [self setCity:[placemark locality] andState:[placemark administrativeArea]];
        MapPoint *mp = [[MapPoint alloc] initWithCoordinate:[newLocation coordinate]
                                                      title:[locationTitleField text]
                                                       date:[dateFormat stringFromDate:today]];
        [mapView addAnnotation:mp];
    }];
}

End Update

Also, it looks as if you may not be using properties as well as you could. Since you have a city and state property, you do not need the city and state instance variables.

Try to change it as such:

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate, MKMapViewDelegate>
{
    CLLocationManager *locationManager;
    IBOutlet MKMapView *mapView;
}

In implementation:

@synthesize city, state
...
- (void)setCity:(NSString *)c andState:(NSString *)s
{
    [self setCity:c];
    [self setState:s];
    NSLog(@"Location 2: %@, %@", city, state);
}

You will not need the extra retain statements because the property copies the value. You must also be sure to call self.city and self.state to get the values.

David V
  • 11,531
  • 5
  • 42
  • 66
  • Yea those extra retains were in hopes to keep the data from being cleared. So how can I get the city and state information to use in my MKAnnotation? It seems as though the completionHandler block is the very last thing that runs in the code regardless of how I structure it. – Kevin_TA Dec 23 '11 at 03:00
  • Thanks, David. I ended up not bothering with the city and state properties. I just sent the information to MapPoint via: [NSString stringWithFormat:@"%@, %@",[placemark locality], [placemark administrativeArea]]; – Kevin_TA Dec 23 '11 at 17:05
  • @DavidV, newbie question related to your answer. Would not the update to the mapView have to be executed on the main thread since it affects UIView? – PhillipOReilly Feb 21 '14 at 01:03