iOS 8 Background Location Update triggered by iBeacon - ios

I am trying to make an app that can be trigged by an iBeacon to wake up (from being killed/suspended/terminated) to record second-by-second GPS information. The GPS recording should then stop when the phone gets out of range of the beacon. I have successfully gotten my app to recognize the didEnterRegion and didExitRegion methods when it comes in and out of range of the iBeacon. In the didEnterRegion method I want to basically say something like [locationManager startUpdatingLocation] so that I can start tracking the user's location. However, when I try to add this line of code, the location updates stop after about 10 seconds.
Later I found an article about background location updates that came with this Github project. I added the BackgroundTaskManager, LocationShareModel, and LocationTracker files to my project. Basically, the idea behind this solution is to continually restart the location manager so it doesn't have the chance for the background task to expire and stop sending updates. However, even with this solution, I only get location updates for a little over 3 minutes.
I have the "Location Updates" and "Use Bluetooth LE accessories" background modes enables. The "Background Fetch" (Background App Refresh) is not enabled, in accordance with this quote from Apple: "In iOS 8 and later, disabling the Background App Refresh setting for the current app or for all apps does not prevent the delivery of location events in the background." My app requests "Always" authorization for location updates.
I cannot figure out how to solve this issue, despite reviewing seemingly endless StackOverflow articles and tutorials. I am testing it on an iPhone 5S running iOS 8.3.0. Any insight would be appreciated. See code excerpts below.
In AppDelegate.m :
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Start recording trip";
notification.soundName = #"Default";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.recording = YES;
[self startAutoTrip];
}
}
- (void) startAutoTrip {
self.locationTracker = [[LocationTracker alloc]init];
[self.locationTracker startLocationTracking];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"Stop recording trip";
notification.soundName = #"Default";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
[self stopAutoTrip];
self.recording = NO;
}
}
- (void)stopAutoTrip {
// stop recording the locations
CLSLog(#"Trying to stop location updates");
[self.locationTracker stopLocationTracking:self.managedObjectContext];
CLSLog(#"Stop location updates");
}
In LocationTracker.m (from tutorial cited above, change 60 sec and 10 sec time intervals to 5 sec and 2 sec). Basically these are the startLocationTracking, didUpdateLocations, and stopLocationTracking methods.
- (void)startLocationTracking {
NSLog(#"startLocationTracking");
if ([CLLocationManager locationServicesEnabled] == NO) {
NSLog(#"locationServicesEnabled false");
UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:#"Location Services Disabled" message:#"You currently have all location services for this device disabled" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[servicesDisabledAlert show];
} else {
CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
if(authorizationStatus == kCLAuthorizationStatusDenied || authorizationStatus == kCLAuthorizationStatusRestricted){
NSLog(#"authorizationStatus failed");
} else {
NSLog(#"authorizationStatus authorized");
CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 10; //meters
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
locationManager.pausesLocationUpdatesAutomatically = NO;
if(IS_OS_8_OR_LATER) {
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
}
}
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
NSLog(#"locationManager didUpdateLocations");
for(int i=0;i<locations.count;i++){
CLLocation * newLocation = [locations objectAtIndex:i];
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 10.0 && newLocation.horizontalAccuracy < 20 && locations.count > 0) {
CLLocationCoordinate2D theLocation = newLocation.coordinate;
CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
self.myLastLocation = theLocation;
self.myLastLocationAccuracy= theAccuracy;
CLLocationCoordinate2D coords[2];
coords[0] = ((CLLocation *)locations.lastObject).coordinate;
coords[1] = newLocation.coordinate;
[self.shareModel.myLocationArray addObject:newLocation];
}
}
//If the timer still valid, return it (Will not run the code below)
if (self.shareModel.timer) {
return;
}
self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
[self.shareModel.bgTask beginNewBackgroundTask];
//Restart the locationMaanger after 1 minute (5 sec)
self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self
selector:#selector(restartLocationUpdates)
userInfo:nil
repeats:NO];
//Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
//The location manager will only operate for 10 seconds to save battery
// 2 sec
if (self.shareModel.delay10Seconds) {
[self.shareModel.delay10Seconds invalidate];
self.shareModel.delay10Seconds = nil;
}
self.shareModel.delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:#selector(stopLocationDelayBy10Seconds)
userInfo:nil
repeats:NO];
}
- (void) restartLocationUpdates
{
NSLog(#"restartLocationUpdates");
if (self.shareModel.timer) {
[self.shareModel.timer invalidate];
self.shareModel.timer = nil;
}
CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 10; //meters
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
locationManager.pausesLocationUpdatesAutomatically = NO;
if(IS_OS_8_OR_LATER) {
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
}
- (void)stopLocationTracking:(NSManagedObjectContext *)managedObjectContext {
NSLog(#"stopLocationTracking");
CLSLog(#"stopLocationTracking");
CLSLog(#"set managedObjectContext %#", managedObjectContext);
self.managedObjectContext = managedObjectContext;
if (self.shareModel.timer) {
[self.shareModel.timer invalidate];
self.shareModel.timer = nil;
}
CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
[locationManager stopUpdatingLocation];
[self saveRun];
[self sendRun];
}

Thank you all for your responses. It is possible to wake your app up from being killed/suspended/terminated using iBeacons, contrary to what Øyvind Hauge said. And unfortunately, adding the background location mode to your plist does not enable indefinite location updates, as others suggested; I was only ever able to get 3 minutes of execution using that method.
I actually found the solution to my question in this StackOverflow article. The solution is to add just a few lines of code to your app delegate - you need to start another location manager that is monitoring for significant location updates. Here are the lines of code that I added to my didFinishLaunchingWithOptions method in my AppDelegate.m file after declaring anotherLocationManager as a property...
self.anotherLocationManager = [[CLLocationManager alloc] init];
self.anotherLocationManager.delegate = self;
[self.anotherLocationManager startMonitoringSignificantLocationChanges];
I never do anything else using this location manager, I just leave it perpetually running in the background, and for some reason this enables indefinite location updates from a regular call to [locationManager startUpdatingLocation]. I am no longer having the location updates mysteriously stop after 3 minutes. It seems very strange that this was the solution, but it was pretty simple to implement, and hopefully this will help others who are dealing with the same problem.

If you set the location background mode in your plist, you can range beacons and get GPS location updates indefinitely. The key to getting this to work is starting a background thread.
You can see an example of how to do this in this blog post about extending beacon ranging on the background. While the blog post mentions this is limited to 3 minutes, when you add the location background mode to your plist, that time limit goes away.
Understand that you may not get AppStore approval for using this background mode unless Apple appreciates your justification for doing so.

So in iOS, location updates will work in background indefinitely ONLY if -
1. You have started location updates in foreground AND
2. You have added Background Location in your plist.
In your case, the OS is waking you up in background and as you've said correctly, you only get 10 seconds of execution time before the OS suspends your app. The workaround for this is basically starting a background task, as you have done to get additional 180 seconds of execution time (this number can change based on OS version).
To understand your issue in depth, you need to know that there are only certain events(like geofence/ibeacon/significant location update) which will wake your app in background, let us call them "wakeup" events. Once any of these event occurs, you have a maximum of 180 seconds of background execution time (using background task) after which your app WILL be suspended, unless any of these events is triggered again, after which you need to restart your background task. I'm not sure how your application works exactly, but if you can ensure that you keep getting these "wakeup" events from the OS for the duration for which you need location updates, you can pretty much keep your app awake in background.
Just to add, I've seen a lot of blog posts that claim that keeping a timer and restarting location updates periodically using that timer works, but I have never been able to use it successfully.

Related

How to get location updates power efficiently with ios when deferredlocationupdatesavailable returns NO

I am trying to defer location updates in ios 11 in order to conserve power. Default seems to be updating as fast as possible (ie every second), so I want to defer the updates or doing something else clever to make a power efficient application.
When implementing CLLocationManager and setting up like this:
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = _sharedInstance = [[LocationManager alloc] init];
[_locationManager requestAlwaysAuthorization];
_locationManager.allowsBackgroundLocationUpdates = true;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter = 0;
_locationManager.pausesLocationUpdatesAutomatically = NO;
_locationManager.activityType = CLActivityTypeFitness;
[CLLocationManager deferredLocationUpdatesAvailable] returns false in didUpdateLocations and thus I get error 11 when trying to defer using the method allowDeferredLocationUpdatesUntilTraveled.
These questions (here and here) indicates that deferring locations updates are no longer supported.
Anyhow, how do you then make ios location applications power efficient when you want updates every x (e.g. 15) seconds, the best (ie gps) accuracy and working/running always in the background?
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;
}
}

Location and accelerometer updates in the background under iOS 10

My app collects location and accelerometer information, and continues to do so in the background if the user requests it. The accelerometer information is collected at about 100 Hz, and it is critical that it be collected at a high rate. The app has worked fine under older versions of iOS, but is failing under iOS 10. I'm looking for a way to continue collecting accelerometer information while in the background.
The method used is similar to that in Receive accelerometer updates in background using CoreMotion framework. I start the location manager:
latitude = 0.0;
longitude = 0.0;
altitude = 0.0;
horizontalAccuracy = -1.0;
verticalAccuracy = -1.0;
if (locationManager == nil && [CLLocationManager locationServicesEnabled]) {
self.locationManager = [[CLLocationManager alloc] init];
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
[locationManager requestWhenInUseAuthorization];
}
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.pausesLocationUpdatesAutomatically = NO;
[locationManager startUpdatingLocation];
}
I implement locationManager:didUpdateLocations:
- (void) locationManager: (CLLocationManager *) manager didUpdateLocations: (NSArray *) locations {
printf("locationManager:didUpdateLocations:\n");
CLLocation *location = locations.lastObject;
latitude = location.coordinate.latitude;
longitude = location.coordinate.longitude;
altitude = location.altitude;
horizontalAccuracy = location.horizontalAccuracy;
verticalAccuracy = location.verticalAccuracy;
}
I start the motion manager:
motionManager = [[CMMotionManager alloc] init];
motionManager.accelerometerUpdateInterval = 1.f/trialFrequency;
[[NSOperationQueue mainQueue] setMaxConcurrentOperationCount: 10];
[motionManager startAccelerometerUpdatesToQueue: [NSOperationQueue mainQueue]
withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error) {
// Flag any error.
if (error) {
NSLog(#"error getting accelerometer update: %#", error);
}
<<<process data>>>
}
];
TARGETS, Capabilities, Background Modes, Location updates is checked.
Under iOS 9 and previous, the motion information is recorded at a rate of around 100 Hz with no problem, but under iOS 10, the motion information stops as soon as the app enters the background.
Is there any way to get the motion information to continue in the background under iOS 10?
Beginning with iOS 9, there is a new call required to enable background processing of location events. It can be used to turn background processing on and off, but defaults to off, so it must be set manually to restore background processing in iOS 8 and prior code.
Add this line when setting up the location manager to allow background processing:
locationManager.allowsBackgroundLocationUpdates = YES;

Problems in efficiently tracking the user in iOS 7 background mode

I am writing a code to constantly track the user applying CoreLocation. Since I cannot keep the GPS on all the time, I use StartMonitoringSignificantLocationChange in my AppDelegate to detect a significant change. I have registered for location in the UIBackgroundMode.
in didUpdateLocations method, I check the current distance from the previously recorded location. If it is significant, I apply StopMonitoringSignificantLocationChange and StartUpdatingLocation to get accurate locations. Meanwhile I initiate a timer (30 secs) to see whether the user is stationary or moving. If the user is not moving anymore, I apply StopUpdatingLocation and StartMonitoringSignificantLocationChange again.
I have also defined a background task in my AppDelegate: -(void)applicationWillResignActive:(UIApplication *)application as follows:
- (void)applicationWillResignActive:(UIApplication *)application
{
if (![[GeoSampleManager sharedManager] isLiveTracking])
{
GeoSampleManager *manager = [HTSGeoSampleManager sharedManager];
[manager.locationManager stopMonitoringSignificantLocationChanges];
self.bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
[manager.locationManager startMonitoringSignificantLocationChanges];
}
}
I close the background task when the app eneters foreground:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if(self.bgTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}
}
And here is my didUpdateLocations method:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation* newLocation = [locations lastObject];
if(self.isLiveTracking)
{
//Test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0 || newLocation.horizontalAccuracy > 200)
{
return;
}
if([self.lastLocation distanceFromLocation:newLocation] > 0)
{
//Create and save a GeoSample
[GeoSampleManager createSampleForLocation:newLocation onTrip:self.activeTrip];
self.lastLocation = newLocation;
}
}
else
{
if([self.lastLocation distanceFromLocation:newLocation] > 0)
{
[self.locationManager stopMonitoringSignificantLocationChanges];
self.idleChecker = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(checkIdle:) userInfo:nil repeats:YES];
[self.locationManager startUpdatingLocation];
self.isLiveTracking = YES;
}
}
}
And finally here is the timer method:
- (void)checkIdle:(NSTimer*)timer
{
if(abs([self.lastLocation.timestamp timeIntervalSinceNow]) >= 30.0)
{
//Stopping the idle-time checking timer
[self.idleChecker invalidate];
self.idleChecker = nil;
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
self.isLiveTracking = NO;
}
}
However, the app is suspended (sometimes after 5-10 secs, sometimes after 10 mins) and stops receiving location updates.Since I am struggling with this problem for more than a month and I have tried almost all possible solution, I really appreciate if you can help me to solve the issue in any way.
Cheers
Backgrounding tasks will die after 10 minutes unless the correct multitasking mode is set (such as a navigation app) in which case you need to keep the GPS on.
You will have to keep the GPS on or play a sound in the background. You say you cannot keep the GPS on all the time, but if this is the case then what you are seeing is likely the expected behavior (or i misread something).
Refer to the different CLLocationAccuracy constants available:
Available at: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CoreLocationConstantsRef/Reference/reference.html#//apple_ref/c/data/kCLLocationAccuracyKilometer
extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation;
extern const CLLocationAccuracy kCLLocationAccuracyBest;
extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
At the very least this "may" help manage your GPS battery consumption if you do keep it running all the time.

iOS GPS Battery drain, how to make it less drain?

My service needs gps. I actually implemented a service, which turns the gps on, checks if the location is valid, and then goes to sleep for some time. (Starting with 5 seconds, and if no movement is detected, it can sleep up to a minute)
After that, I start the gps again, and get a new location.
But the battery drain is still high! Ive used locMgr.distanceFilter = 10.0f and desiredAccurady = NearestTenMeters.
How do I minimize battery drain more?
This is how I handle it. After I grab the location I store it in a NSDictionary. Then if I need to location again I return the NSDictionary instead of turning the GPS back on. After 2 minutes I reset the NSDictionary (you can adjust the time to what best suites you app). Then the next time I need the location after the NSDictionary was reset I grab a new location from the GPS.
- (NSDictionary *) getCurrentLocation {
if (self.currentLocationDict == nil) {
self.currentLocationDict = [[NSMutableDictionary alloc] init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
locationManager.distanceFilter = kCLDistanceFilterNone;
[locationManager startUpdatingLocation];
CLLocation *myLocation = [locationManager location];
[self.currentLocationDict setObject:[NSString stringWithFormat:#"%f", myLocation.coordinate.latitude] forKey:#"lat"];
[self.currentLocationDict setObject:[NSString stringWithFormat:#"%f", myLocation.coordinate.longitude] forKey:#"lng"];
[locationManager stopUpdatingLocation];
[locationManager release];
//Below timer is to help save battery by only getting new location only after 2 min has passed from the last time a new position was taken. Last location is saved in currentLocationDict
[NSTimer scheduledTimerWithTimeInterval:120 target:self selector:#selector(resetCurrentLocation) userInfo:nil repeats:NO];
}
return self.currentLocationDict;
}
- (void) resetCurrentLocation {
NSLog(#"reset");
[currentLocationDict release];
self.currentLocationDict = nil;
}

Core location gives old location whenever comes from background

I have a CoreLocation manager in VC, when user pressed "get direction" button, I initalize location manager, and app opens google map direction with current location and some pre defined destination location.
Here is my problem, if app is not in background state, current location nearly always true, bu if app calling from background in same VC and user pressed again "get direction" button , current location generally shows old locations. In short, I'm troubling with multitasking and timestamp of retrieved locations did not solved my problem.
IBAction:
if ( self.locationManager ) {
[_locationManager release];
self.locationManager = nil;
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationTimer = [NSTimer scheduledTimerWithTimeInterval:LOCATION_TIMER target:self selector:#selector(stopUpdatingLocationTimer) userInfo:nil repeats:NO];
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
[self.locationManager startUpdatingLocation];
Core Location Delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%f",locationAge);
if (locationAge > 3.0)
return;
if (newLocation.horizontalAccuracy < 0)
return;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy ) {
self.currentLocation = newLocation;
if (self.currentLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) {
[self stopUpdatingLocations:YES];
}
}
}
In your example locationAge is a negative representation of the number of seconds since the timestamp of newLocation. This means that locationAge will never be greater than 3 and you're effectively letting every update through the sieve.
Set locationAge like this:
NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceNow];
For those who encounter same problem,
Also, some tutorials related with core location on web, lead me this problem.
Of course, I keep CLLocation ivar in my VC, whenever CLLocation ivar
sets and google maps called, my app goes to background.
Then, my app calls from background by user, and start updating locations,
and old CLLocation ivar is not nil and probably best horizantal accuracy then
newly comes. Therefore;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy )
this line cause problems, and old location in CLLocation ivar
never replaced.
So I changed viewDidDisappear like this and I assigned nil value to CLLocation variable and works perfectly.
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.locationManager stopUpdatingLocation]; // CLLocationManager
self.locationManager = nil;
[self.locationTimer invalidate]; // NSTimer
self.locationTimer = nil;
self.currentLocation = nil; // CLLocation
}
p.s : thank you Mark Adams

Resources