Ios, startMonitoringSignificantLocationChanges - sometimes interrupts monitoring

I have a weird problem updating user location. Sometimes my application updates the location, but occasionally interrupts the update. I do not know where the problem is, my code (from AppDelegate.m) is below:

- (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"Went to Background"); // Only monitor significant changes [locationManager startMonitoringSignificantLocationChanges]; } - (void)applicationDidBecomeActive:(UIApplication *)application { // Start location services locationManager = [[CLLocationManager alloc] init]; locationManager.desiredAccuracy = kCLLocationAccuracyBest; // Only report to location manager if the user has traveled 1000 meters locationManager.distanceFilter = 1000.0f; locationManager.delegate = self; locationManager.activityType = CLActivityTypeAutomotiveNavigation; [locationManager stopMonitoringSignificantLocationChanges]; [locationManager startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { // Check if running in background or not BOOL isInBackground = NO; if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { isInBackground = YES; } if (isInBackground) { // If we're running in the background, run sendBackgroundLocationToServer [self sendBackgroundLocationToServer:[locations lastObject]]; } else { // If we're not in the background wait till the GPS is accurate to send it to the server if ([[locations lastObject] horizontalAccuracy] < 100.0f) { [self sendDataToServer:[locations lastObject]]; } } } -(void) sendBackgroundLocationToServer:(CLLocation *)location { bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:bgTask]; }]; // Send the data [self sendDataToServer:location]; if (bgTask != UIBackgroundTaskInvalid) { [[UIApplication sharedApplication] endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; } } -(void) sendDataToServer:(CLLocation *)newLocation { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *lat = [NSString stringWithFormat:@"%.8f", newLocation.coordinate.latitude]; NSString *lng = [NSString stringWithFormat:@"%.8f", newLocation.coordinate.longitude]; [APIConnection SaveMyPositionWitLat:lat withLng:lng]; }); } 

I need to update the location every hour or if the user changes the location for more than 1000 m. I chose the second way to save battery, but my solution does not work as I need.

I would really appreciate any help with this, thanks in advance!

+6
source share
1 answer

I can’t say for sure if this is all of you, but I would make the following changes:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Moved to didFinishLaunching... you should not be recreating every time app // becomes active. You can check for locations key in the options Dictionary if // it is necessary to alter your setup based on background launch // Start location services locationManager = [[CLLocationManager alloc] init]; locationManager.desiredAccuracy = kCLLocationAccuracyBest; // Only report to location manager if the user has traveled 1000 meters locationManager.distanceFilter = 1000.0f; locationManager.delegate = self; locationManager.activityType = CLActivityTypeAutomotiveNavigation; // Start monitoring significant locations here as default, will switch to // update locations on enter foreground [locationManager startMonitoringSignificantLocationChanges]; // Hold in property to maintain reference self.locationManager = locationManager; } 

Following your example, this will be all that remains in your didBecomeActive method (I would use willEnterForeground ):

 - (void)willEnterForeground:(UIApplication *)application { [self.locationManager stopMonitoringSignificantLocationChanges]; [self.locationManager startUpdatingLocation]; } 

Entering the background, return to significant changes in location:

 - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"Went to Background"); // Need to stop regular updates first [self.locationManager stopUpdatingLocation]; // Only monitor significant changes [self.locationManager startMonitoringSignificantLocationChanges]; } 

In the delegate method, I recommend taking out all conditional background tests. I wrap the background task ID in case the application is in the background or goes into the background before terminating. I also respond to the global thread, so we are not blocking the UI (optional):

 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { UIApplication *app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier locationUpdateTaskID = [app beginBackgroundTaskWithExpirationHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ if (locationUpdateTaskID != UIBackgroundTaskInvalid) { [app endBackgroundTask:locationUpdateTaskID]; locationUpdateTaskID = UIBackgroundTaskInvalid; } }); }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // You might consider what to do here if you do not ever get a location accurate enough to pass the test. // Also consider comparing to previous report and verifying that it is indeed beyond your threshold distance and/or recency. You cannot count on the LM not to repeat. if ([[locations lastObject] horizontalAccuracy] < 100.0f) { [self sendDataToServer:[locations lastObject]]; } // Close out task Identifier on main queue dispatch_async(dispatch_get_main_queue(), ^{ if (locationUpdateTaskID != UIBackgroundTaskInvalid) { [app endBackgroundTask:locationUpdateTaskID]; locationUpdateTaskID = UIBackgroundTaskInvalid; } }); }); } 

See my project, TTLocationHandler

on Github for a few more examples of using Core Location, how you want to use it.

+31
source

All Articles