This answer might be a little off, because it is actually not possible anymore to use the deffering functionality even the doc has not been removed. But the intention was to switch on/off the location in intervals to avoid having it on all the time to conserve power.
To getting close to turning on/off completely, one might togge between high and low accuracy, this will save power for sure. (high accuracy typically <10m will use GPS module, low accuracy >500m will typically use AGPS.
First, start an NSTimer with the interval you want, then start updating with high accuracy. When receiving a location in didUpdateLocations, change from high accuracy to low accuracy. The callback of NSTimer requests a new high accuracy location update (ie calls setupHighAccuracy
). The timer thus sets the frequency of the high accuracy updates. This will also work in the background because the location service is still running. If stopping updates, the app will stop in the background. When stopping and at once starting the location manager again, it will immediately call didUpdateLocation, but check the timestamp, the location may be buffered.
Showing some snippets below to get going. Production code will need more filtering and testing:
@property (retain, nonatomic) NSTimer *atimer;
static BOOL _lowAccuracy;
- (void)timerCallback {
[self setupHighAccuracy];
}
- (void)setupTimer
{
if(self.atimer != nil)
{
return;
}
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTaskId =
[app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
}];
dispatch_async( dispatch_get_main_queue(), ^{
self.atimer = [NSTimer scheduledTimerWithTimeInterval:15.0 // consider higher interval
target:self
selector:@selector(timerCallback)
userInfo:nil
repeats:YES];
}
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
});
}
- (void)setupHighAccuracy
{
if(_lowAccuracy)
{
[_locationManager performSelectorOnMainThread:@selector(stopUpdatingLocation) withObject:nil waitUntilDone:YES];
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // or kCLLocationAccuracyBest, tune yourself
_locationManager.activityType = CLActivityTypeFitness;
_locationManager.distanceFilter = 15; // or 0, tune yourself
_lowAccuracy = false;
[_locationManager performSelectorOnMainThread:@selector(startUpdatingLocation) withObject:nil waitUntilDone:YES];
}
}
- (void)setupLowAccuracy
{
if(!_lowAccuracy)
{
s_initialized = true;
[_locationManager performSelectorOnMainThread:@selector(stopUpdatingLocation) withObject:nil waitUntilDone:YES];
_locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
_locationManager.activityType = CLActivityTypeFitness;
_locationManager.distanceFilter = 3000;
_lowAccuracy = true;
[_locationManager performSelectorOnMainThread:@selector(startUpdatingLocation) withObject:nil waitUntilDone:YES];
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *location = locations.lastObject;
if(!_lowAccuracy) {
// update system with location here
[_locationManager.delegate setupLowAccuracy];
self.s_lastLocation = location;
}
}