I am using MKReverseGeocoder (reversegeocoder) to retrieve user's current location. I am calling reversegeocoder in locationDidUpdatedToLocation method of CLLocation Manager.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if(!reverseGeocoder )
{
NSLog(#"geocoder is nill");
reverseGeocoder=[[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
reverseGeocoder.delegate=self;
[reverseGeocoder start];
NSLog(#"geocoder allocated");
}
else
{
NSLog(#"geocoder is not nill");
if(reverseGeocoder.querying)
{
//do nothing ;
}
else
[reverseGeocoder release];
}
}
.querying property is used to ensure that reversegeocoder should be released only when It has completed its query. But when application crashes within 3-4 seconds of running with error message
-[MKReverseGeocoder isQuerying]: message sent to deallocated instance
What am I missing here?
Thanks for any help in advance.
Could it be because you haven't set the geocoder's delegate to nil before releasing it? Or that you haven't nilled the pointer?
Try this:
if(reverseGeocoder.querying)
{
//do nothing ;
}
else
{
[reverseGeocoder setDelegate:nil];
[reverseGeocoder release];
reverseGeocoder = nil;
}
Related
I all I wonder if anybody can help me once again? I have moved my location coding from my View controller into an NSObject. I have then called this from the App Delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Updating Location
[Location sharedLocation];
//Timer for reloading the XML
recheckTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(recheckLocation) userInfo:nil repeats:YES];
return YES:
}
I have set a timer for when I want this process ran again
-(void)recheckLocation
{
//Updating Location
[Location sharedLocation];
NSLog(#"Timer Triggered");
}
The only thing is when the timer triggers the sharedlocation does not get updated again?? Please can anybody help in advance? Many thanks, Jon.
#import "Location.h"
#implementation Location
#synthesize locationManager;
- (id)init {
self = [super init];
if(self) {
self.locationManager = [CLLocationManager new];
[self.locationManager setDelegate:self];
[self.locationManager setDistanceFilter:500];//Metres
[self.locationManager setHeadingFilter:90];
[self.locationManager startMonitoringSignificantLocationChanges];
}
return self;
}
+ (Location*)sharedLocation {
static Location* sharedLocation;
if(!sharedLocation) {
#synchronized(sharedLocation) {
sharedLocation = [Location new];
}
}
return sharedLocation;
}
//LOCATION CODING
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError' %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Failed to Get Your Current Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
//Resolve Web Address
webAddressResolved = [NSString stringWithFormat:#"XZYYFASDFA%f,%f.xml", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude];
NSLog(#"Address Resolved %#", webAddressResolved);
}
//Stop Location Manager
[locationManager stopMonitoringSignificantLocationChanges];
}
Well what yo defined here is a singleton of Location and the purpose of shared location does not seem to update the location as it says in the code comments
what the sharedInstance does is return a reference that is once initialized and is used the same everywhere in the whole code.It gives you the location instance in return, which you are not retrieving anywhere and using it.You just call it but not use it.
Define a method to update location and call it after getting the memory from the location using
Location *sharedLoc=[Location sharedLocation];
and call the method to update the location as
[sharedLoc updateLocation];
Location.h
-(void)updateLocation;
in Location .m
-(void)updateLocation
{
//Code for updation purpose
}
I want to get a single location and then stop getting notification from CLLocationManager.
I do it with this:
-(id)initWithDelegate:(id <GPSLocationDelegate>)aDelegate{
self = [super init];
if(self != nil) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
delegate = aDelegate;
}
return self;
}
-(void)startUpdating{
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[locationManager stopUpdatingLocation];
[delegate locationUpdate:newLocation];
}
The issue is that even when I do [locationManager stopUpdatingLocation];
in - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:
I still get notification, any idea why it happen?
Maybe try my solution. I'm build two functionals for handling LocationManger Obj.
The first function is startUpdates for handle start update location. Code look like this :
- (void)startUpdate
{
if ([self locationManager])
{
[[self locationManager] stopUpdatingLocation];
}
else
{
self.locationManager = [[CLLocationManager alloc] init];
[[self locationManager] setDelegate:self];
[[self locationManager] setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[[self locationManager] setDistanceFilter:10.0];
}
[[self locationManager] startUpdatingLocation];
}
The second function is stopUpdate for handle CLLocationDelegate to stop update location. Code look like this :
- (void)stopUpdate
{
if ([self locationManager])
{
[[self locationManager] stopUpdatingLocation];
}
}
So, for CLLocationManagerDelegate should be look like this :
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
self.attempts++;
if(firstPosition == NO)
{
if((howRecent < -2.0 || newLocation.horizontalAccuracy > 50.0) && ([self attempts] < 5))
{
// force an update, value is not good enough for starting Point
[self startUpdates];
return;
}
else
{
firstPosition = YES;
isReadyForReload = YES;
tempNewLocation = newLocation;
NSLog(#"## Latitude : %f", tempNewLocation.coordinate.latitude);
NSLog(#"## Longitude : %f", tempNewLocation.coordinate.longitude);
[self stopUpdate];
}
}
}
Inside this function above, i'm correct only the best location for update location. I hope my answer will help, Cheers.
I think that the reason of your problem is in distance filter. As docs say:
Use the value kCLDistanceFilterNone to be notified of all movements. The default value of this property is kCLDistanceFilterNone.
So you just have what you've set - continuous updates.
My ultimate goal is that i need to send lat and logitude to web server, every time when location changes.
I am using below code for sending lat and longitude of a device to a web server after every 2 minutes but it is not giving sometimes correct latitude and longitude as location changes.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation
{
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"Location Age%#",[NSString stringWithFormat:#"%d",locationAge]);
if (locationAge > 5) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
NSString *stringUrl;
// BOOL check = FALSE;
NSLog(#"Before condition condition");
if(bestEffortAtLocation == nil || bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy){
NSLog(#"condition");
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= locmanager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
[locmanager stopUpdatingLocation];
locmanager.delegate = nil;
}
//check = TRUE;
}
stringUrl = [NSString stringWithFormat:URLSAVELAT,stringUserId,[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.latitude],[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.longitude]];}
For location manager i am using below code
{
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
locmanager.distanceFilter = 10.0;
//locmanager.distanceFilter = kCLDistanceFilterNone;
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locmanager startUpdatingLocation];
}
Any,even small help would be appreciated, Thank u in advance
You should use the location update call backs from the API and use updateLocation method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) {
[self.delegate locationUpdate:newLocation];
}
}
Then in the viewcontroller do this:
- (void)locationUpdate:(CLLocation *)location {
//DO WHATEVER YOU WANT HERE, INCLUDING SENDING TO SERVER
}
You also need to define two protocol methods, one of which is the locationUpdate:
#protocol CoreLocationControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
I would not recommend doing all that you do in the didUpdateLocation: method.
i am creating an application in which i want to get the current location of the user where he is and display it on the map and when the user reaches the destination location from current location the destination location should also be pointed in the map along the direction of travel.
In my xib i have added a button & on action(showDirectionsToHere) of button i have called map
I have added the following code in my appdelegate but it gives me an error:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
[manager stopUpdatingLocation];
printf("\n Latitude = " "\n Longitude = " " ",[NSString stringWithFormat:#"%.7f",newLocation.coordinate.latitude],[NSString stringWithFormat:#"%.7f",newLocation.coordinate.longitude]);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CLLocationManager *locationManager = [[[CLLocationManager alloc]init]autorelease];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
//[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
printf("\nerror");
}
- (IBAction)showDirectionsToHere {
CLLocationCoordinate2D currentLocation = [self getCurrentLocation]; // LINE 1
NSString* url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=old\%20Location&daddr=%f,%f", newLocation.latitude, newLocation.longitude];//Line 2
}
in line 1 of action(showDirectionsHere) i get error of invalid initializer
in Line 2 i get error that newLocation undeclared.
Please help me
NSString* url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=old\%20Location&daddr=%f,%f", currentLocation.latitude, currentLocation.longitude];
Can you post the code for getCurrentLocation so that we can see what it returns.
The variable newLocation is undeclared. I think you meant currentLocation in the function.
I already know how to use the CLLocationManager, so I could do it the hard way, with delegates and all that.
But I'd like to have a convenience method that just gets the current location, once, and blocks until it gets the result.
What I do is implement a singleton class to manage updates from core location. To access my current location, I do a CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; If you wanted to block the main thread you could do something like this:
while ([[LocationManager sharedInstance] locationKnown] == NO){
//blocking here
//do stuff here, dont forget to have some kind of timeout to get out of this blocked //state
}
However, as it has been already pointed out, blocking the main thread is probably not a good idea, but this can be a good jumping off point as you are building something. You will also notice that the class I wrote checks the timestamp on location updates and ignores any that are old, to prevent the problem of getting stale data from core location.
This is the singleton class I wrote. Please note that it is a little rough around the edges:
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
#interface LocationController : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
+ (LocationController *)sharedInstance;
-(void) start;
-(void) stop;
-(BOOL) locationKnown;
#property (nonatomic, retain) CLLocation *currentLocation;
#end
#implementation LocationController
#synthesize currentLocation;
static LocationController *sharedInstance;
+ (LocationController *)sharedInstance {
#synchronized(self) {
if (!sharedInstance)
sharedInstance=[[LocationController alloc] init];
}
return sharedInstance;
}
+(id)alloc {
#synchronized(self) {
NSAssert(sharedInstance == nil, #"Attempted to allocate a second instance of a singleton LocationController.");
sharedInstance = [super alloc];
}
return sharedInstance;
}
-(id) init {
if (self = [super init]) {
self.currentLocation = [[CLLocation alloc] init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[self start];
}
return self;
}
-(void) start {
[locationManager startUpdatingLocation];
}
-(void) stop {
[locationManager stopUpdatingLocation];
}
-(BOOL) locationKnown {
if (round(currentLocation.speed) == -1) return NO; else return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120) {
self.currentLocation = newLocation;
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[error description] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(void) dealloc {
[locationManager release];
[currentLocation release];
[super dealloc];
}
#end
There is no such convenience and you shouldn't create your own. "Blocks until it gets the result" is extremely bad programming practice on a device like the iPhone. It can take seconds to retrieve a location; you should never make your users wait like that, and delegates ensure they don't.
There are no "convenience methods" unless you code them yourself, but you'd still need to implement the delegate methods in whatever custom code you use to make things "convenient."
The delegate pattern is there for a reason, and as delegates are a big part of Objective-C, I recommend you get comfortable with them.
I appreciated the answer by Brad Smith. Implementing it I discovered that one of the methods he employs is deprecated as of iOS6. To write code that will work with both iOS5 and iOS6, use the following:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (abs([[locations lastObject] timeIntervalSinceDate:[NSDate date]]) < 120) {
[self setCurrentLocation:[locations lastObject]];
}
}
// Backward compatibility with iOS5.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSArray *locations = [NSArray arrayWithObjects:oldLocation, newLocation, nil];
[self locationManager:manager didUpdateLocations:locations];
}
I simplified and combined multiple answers to where the location is only updated if it's valid.
It also works under OSX as well as iOS.
This assumes the use-case where the current location is suddenly desired by the user. If it takes more than 100 ms in this example, it's considered an error. (Assumes the GPS IC &| Wifi (Apple's Skyhook clone) is already fired up and has a good fix already.)
#import "LocationManager.h"
// wait up to 100 ms
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100];
if (!location) {
NSLog(#"no location :(");
return;
}
// location is good, yay
https://gist.github.com/6972228