I need to know where my users are from, so I made a little singleton object which gets the coordinates and uses mapkit to get the country code I need.
Here's my header file:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#define TW_GEO_CODER_CHANGED_STATE @"TW_GEO_CODER_CHANGED_STATE"
@interface TWGeoCoder : NSObject <CLLocationManagerDelegate, MKReverseGeocoderDelegate>
{
CLLocationManager *locationManager;
MKReverseGeocoder *geoCoder;
NSString *currentCountryIsoCode;
}
+ (TWGeoCoder*) sharedTWGeoCoder;
-(void) startGeoCoder;
-(void) stopGeoCoder;
@property (nonatomic, retain) NSString *currentCountryIsoCode;
@end
And the implementation:
#import "TWGeoCoder.h"
@implementation TWGeoCoder
static TWGeoCoder* _singleton;
+ (TWGeoCoder*) sharedTWGeoCoder
{
@synchronized([TWGeoCoder class])
{
if (_singleton == nil)
{
_singleton = [[TWGeoCoder alloc] init];
}
}
return _singleton;
}
- (void)startGeoCoder
{
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
}
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.purpose = NSLocalizedString(@"#LocalizationPurpose",nil);
[locationManager startUpdatingLocation];
}
- (void) stopGeoCoder
{
if (geoCoder != nil)
{
[geoCoder cancel];
[geoCoder release];
geoCoder = nil;
}
if (locationManager != nil)
{
[locationManager stopUpdatingLocation];
[locationManager release];
locationManager = nil;
}
}
#pragma mark -
#pragma mark locationManager Delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (geoCoder == nil)
{
geoCoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
}
geoCoder.delegate = self;
[geoCoder start];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"locationManager:%@ didFailWithError:%@", manager, error);
[self stopGeoCoder];
}
#pragma mark -
#pragma mark reverseGeocoder Delegate
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
self.currentCountryIsoCode = placemark.countryCode;
[[NSNotificationCenter defaultCenter] postNotificationName:TW_GEO_CODER_CHANGED_STATE
object:self];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
NSLog(@"reverseGeocoder:%@ didFailWithError:%@", geocoder, error);
[self stopGeoCoder];
}
#pragma mark -
#pragma mark Synthesizes
@synthesize currentCountryIsoCode;
@end
Well, calling stopGeoCoder method makes my app crash, even calling it via performSelectorOnMainThread...
The problem is in these lines:
if (geoCoder != nil)
{
[geoCoder cancel];
[geoCoder release];
geoCoder = nil;
}
It seems like MKReverseGeocoder become really angry when I try to release it! I get the crash only on the "didFail" method. Actually, when it finds the placemark, another class will get the notification, does something and call stopGeocoder and... it doesn't crash! WTF?