I’m working on an application which periodically obtains the user’s location. The big problem is that sometimes the app gets stuck, no more updates are delivered. Even if I (kill and) restart my app, nothing changes. (The accuracy values set for location manager are near 100-200 meters.)
BUT, when I start the Google Maps App, in a few seconds it gets a very accurate location (which is delivered to my app to if I switch back). Why ?
Here are some relevant code parts :
The timerFiredAction is called periodically by the timer.
-(void) timerFiredAction
{
if (isStillWaitingForUpdate)
{
successiveTimerActivationCount ++;
// force LM restart if value too big , e.g. 30 ( stop + start )
return;
}
successiveTimerActivationCount = 0 ;
isStillWaitingForUpdate = YES;
/* isRecordingX is always true */
if (isSignificant && isRecordingSig) [self startSignificant ];
if (isGPS && isRecordingGPS) [self startGps];
}
// this is called in delegate method only
-(void) timerStopLocationServices
{
isStillWaitingForUpdate = NO;
if (isGPS) [ self stopGps] ;
if (isSignificant) [self stopSignificant];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// verify accuracy and stuff
if ( isStillWaitingForUpdate && _other_validations_ )
{
// store it
[self timerStopLocationServices] ;
}
}
The start and stop methods simply verifiy if the locationmanager is nil, if yes they call createManager and then call start & stopUpdatingLocation.
The creation of the LM looks like this :
-(void)createManager
{
@synchronized (self)
{
if (locationManager != nil) {
[self releaseManager]; // stop timer, stop updating , reelase previous if exists
}
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
double desired;
// accuracy is an init param, snap to one smaller constant
// generally 100-200
if (accuracy >= kCLLocationAccuracyThreeKilometers) desired = kCLLocationAccuracyThreeKilometers; else
if (accuracy >= kCLLocationAccuracyKilometer) desired = kCLLocationAccuracyKilometer; else
if (accuracy >= kCLLocationAccuracyHundredMeters) desired = kCLLocationAccuracyHundredMeters; else
if (accuracy >= kCLLocationAccuracyNearestTenMeters) desired = kCLLocationAccuracyNearestTenMeters; else
if (accuracy >= kCLLocationAccuracyBest) desired = kCLLocationAccuracyBest; else
if (accuracy >= kCLLocationAccuracyBestForNavigation) desired = kCLLocationAccuracyBestForNavigation;
locationManager.desiredAccuracy = desired;
locationManager.distanceFilter = distanceFilter;
}
}
Did anyone experienced something like this? Any ideas are welcome 🙂
Thanks!
I can at least confirm “blocked location managers”, though in a slightly different context:
From my experience, if you create two location managers with different accuracy settings, start updates for both and then only stop updates for the one with the higher accuracy requirement, then the other one no longer receives any updates.
You are apparently only using one manager, but the way your manager gets stuck seems to be the same: In the case described above, updates can also be restarted by using the map application (or any similar).
My workaround is the following: Whenever I stop one manager, I also reset the distance filters of all others (stored in an
NSSetcalledmyCLLocationManagers), like the following:This seems to work more reliably than my previous woraround (which was to stop and restart the managers).
Note that
kCLLocationAccuracyBestForNavigationandkCLLocationAccuracyBestare (currently) negative values, and that in general, you shouldn’t rely on the specific values of all those constants – there’s no guarantee thatkCLLocationAccuracyHundredMeters==100(although currently true). I only mention this because it appears like you are directly comparing an “accuracy” variable in meters with those constants.