Having Trouble with the Reverse Geocoder challenge


#1

After having consulted as much of the iOS Reference Library that I think is relevant, I’m still having trouble running Reverse Geocoding.

Even before that – what’s supposed to be the end result? Am I supposed to see the name of the city and state in the Annotations? Or will they pop up once Whereami zooms to the current location?

Here’s my code for my WhereamiAppDelegate.h file:

[code]#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface WhereamiAppDelegate : NSObject
<UIApplicationDelegate, CLLocationManagerDelegate, MKMapViewDelegate,
UITextFieldDelegate, MKReverseGeocoderDelegate>
{
CLLocationManager *locationManager;

IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
IBOutlet UITextField *locationTitleField;
IBOutlet MKReverseGeocoder *reverseGeocoder;

}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet MKReverseGeocoder *reverseGeocoder;

  • (void)findLocation;
  • (void)foundLocation:(CLLocation *)loc;
  • (IBAction)reverseGeocodeCurrentLocation;

@end
[/code]

And here’s the implementation. Note: this compiles successfully but warns of an incomplete implementation.

[code]#import “WhereamiAppDelegate.h”
#import “MapPoint.h”

@implementation WhereamiAppDelegate

@synthesize window=_window, reverseGeocoder;

  • (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    // Create location manager object
    locationManager = [[CLLocationManager alloc] init];

    [locationManager setDelegate:self];

    // We want all results from the location manager
    [locationManager setDistanceFilter:kCLDistanceFilterNone];

    // And we want it to be as accurate as possible
    // regardless of how much time/power it takes
    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

    // [locationManager startUpdatingLocation];
    [worldView setShowsUserLocation:YES];

    [[self window] makeKeyAndVisible];
    return YES;
    }

  • (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
    fromLocation:(CLLocation *)oldLocation
    {
    NSLog(@"%@", newLocation);

    // How many seconds ago was this new location created?
    NSTimeInterval t = [[newLocation timestamp] timeIntervalSinceNow];

    // CLLocationManagers will return the last found location of the
    // device first, you don’t want that data in this case.
    // If this location was made more than 3 minutes ago, ignore it.
    if (t <= -180) {
    // This is cached data, you don’t want it, keep looking
    return;
    }

    [self foundLocation:newLocation];
    }

  • (void)locationManager:(CLLocationManager *)manager
    didFailWithError:(NSError *)error
    {
    NSLog(@“Could not find location: %@”, error);
    }

  • (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)u
    {
    CLLocationCoordinate2D loc = [u coordinate];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
    [worldView setRegion:region animated: YES];
    }

  • (BOOL)textFieldShouldReturn:(UITextField *)tf
    {
    // This method isn’t implemented yet - but will be soon.
    [self findLocation];

    [tf resignFirstResponder];

    return YES;
    }

  • (void)findLocation
    {
    [locationManager startUpdatingLocation];
    [activityIndicator startAnimating];
    [locationTitleField setHidden:YES];
    }

  • (void)foundLocation:(CLLocation *)loc
    {
    CLLocationCoordinate2D coord = [loc coordinate];

    // Create an instance of MapPoint with the current data
    MapPoint *mp = [[MapPoint alloc] initWithCoordinate:coord
    title:[locationTitleField text]];

    // Add it to the map view
    [worldView addAnnotation:mp];

    reverseGeocoder = [[[MKReverseGeocoder alloc] initWithCoordinate:coord] autorelease];
    [reverseGeocoder setDelegate:self];
    [reverseGeocoder start];

    // MKMapView retains its annotations, we can release…why?
    [mp release];

    // Zoom the region to this location
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
    [worldView setRegion:region animated:YES];

    [locationTitleField setText:@""];
    [activityIndicator stopAnimating];
    [locationTitleField setHidden:NO];
    [locationManager stopUpdatingLocation];

}

  • (void)dealloc
    {
    if ([locationManager delegate] == self)
    [locationManager setDelegate:nil];

    [locationManager release];
    [_window release];
    [super dealloc];
    }

  • (IBAction)reverseGeocodeCurrentLocation
    {
    self.reverseGeocoder =
    [[[MKReverseGeocoder alloc] initWithCoordinate:worldView.userLocation.location.coordinate] autorelease];
    reverseGeocoder.delegate = self;
    [reverseGeocoder start];
    }

  • (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
    {
    NSLog(@“MKReverseGeocoder has failed.”);
    }

@end[/code]


#2

I am a rookie so this may not be the best way to use the MKReverseGeoCoder, but here is my attempt at help. Don’t declare MKReverseGeocoder as an IBOutlet, just use it like the location manager in the example. You’ll need to add the delegate protocol for the reverseGeocoder object to your header for the whereamiAppDelegate. Then add the two functions from the protocol to your implementation file. Then you’ll need to send your reverseGeocoder object a msg to start at an appropriate place in the code. When implemented correctly it will give you an MKPlacemark Class object that you can get the info you need from to add to your annotation. I have another thread going with a more complete description of this implementation that I just posted. Feel free to take a look at that and comment as well. I didn’t put more info here because I didn’t want to drop any unwanted spoiler info on you.


#3

Tried that out, along with your code from the other thread. When running the program, the value of the placemark shows up as (null) in the console.

Thinking about tabling this for the time being.