ios, startMonitoringSignificantLocationChanges - sometimes breaks monitoring

I have strange problem with updating user's location. Sometimes my app updates location but from time to time breaks updating. I do not know where is problem, 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 location every hour or if user change location more then 1000m. I chose the second way in order to save battery but my solution do not work as I need.

I would greatly appreciate any help on this, Thanks in advance!

Answers


I can't say for sure if this is all of you problem 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 lead, this would be all that remains in your didBecomeActive method (I would use willEnterForeground instead):

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

Entering into background, go back to significant location changes only:

- (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 your delegate method, I recommend taking out all the conditional background testing. I am wrapping in background task identifier in case the app is in the background or goes into the background before finish. I am also responding on global thread so we don't block 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 some more examples of using Core Location the way you wish to use it.


Need Your Help

Why isn't TextBox.Text in WPF animatable?

wpf text animation textbox textblock

Ok, I have just run into something that is really catching me off-guard.