3

I try to invoke URL API at the best GPS location. User clicks the button that fires findMe method to set up desiredAccuracy and distanceFilter and run [self.locationManager startUpdatingLocation].

I check the best vertical and horizontal accuracy and if they don't change in the next iteration I run API and [self.locationManager stopUpdatingLocation]

The point is that after that the best accuracy is changed and -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation is run a few times even if I stop updating location.

-(void)findMe {
  self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  self.locationManager.distanceFilter = kCLDistanceFilterNone;
  [self.locationManager startUpdatingLocation];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
  double longitude = newLocation.coordinate.longitude;
  double latitude = newLocation.coordinate.latitude;

  if ( ((_bestVertivalAccuracy == 0) || (_bestVertivalAccuracy > newLocation.verticalAccuracy))
    || ((_bestHorizontalAccuracy == 0) || (_bestHorizontalAccuracy > newLocation.horizontalAccuracy)) ) {
      NSLog(@"bestVer: %f", _bestVertivalAccuracy);
      NSLog(@"bestHor: %f", _bestHorizontalAccuracy);
      NSLog(@"Given ver: %f", newLocation.verticalAccuracy);
      NSLog(@"Given hor: %f", newLocation.horizontalAccuracy);
      NSLog(@"-------------------------------------------------------");

      _bestVertivalAccuracy = newLocation.verticalAccuracy;
      _bestHorizontalAccuracy = newLocation.horizontalAccuracy;
      return;
  }

  [_locationManager stopUpdatingLocation];

  [POSharedLocation sharedInstance].lng = longitude;
  [POSharedLocation sharedInstance].lat = latitude;
  [POSharedLocation sharedInstance].showUserLocation = YES;

  NSLog(@"Longitude : %f", longitude);
  NSLog(@"Latitude : %f", latitude);
  NSLog(@"Acc. Ver: %f", newLocation.verticalAccuracy);
  NSLog(@"Acc. Hor: %f", newLocation.horizontalAccuracy);
  NSLog(@"-------------------------------------------------------");

  _resultsVC = [[ResultsListViewController alloc] init];
  UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:_resultsVC];

  NSString *locationQuery = [NSString stringWithFormat:@"/json?method=find&lat=%f&lng=%f&distance=%f", latitude, longitude, _distance];

  NSString *url = [API_URL stringByAppendingString:locationQuery];
  NSString* urlEncoded = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];


  // For debuging only
  NSLog(@"URL: %@", urlEncoded);

  NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlEncoded]];

  // Run an asynchronous connection and download the JSON
  (void)[[NSURLConnection alloc] initWithRequest:request delegate:_resultsVC startImmediately:YES];
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

  [self presentModalViewController:navVC animated:YES];
  [navVC release];
}

And the output:

2013-05-30 12:59:13.906 MyApp[30569:907] bestVer: 0.000000
2013-05-30 12:59:13.918 MyApp[30569:907] bestHor: 0.000000
2013-05-30 12:59:13.922 MyApp[30569:907] Given ver: 3.000000
2013-05-30 12:59:13.927 MyApp[30569:907] Given hor: 50.000000
2013-05-30 12:59:13.933 MyApp[30569:907] -------------------------------------------------------
2013-05-30 12:59:14.112 MyApp[30569:907] Longitude : 16.934037
2013-05-30 12:59:14.114 MyApp[30569:907] Latitude : 51.096827
2013-05-30 12:59:14.116 MyApp[30569:907] Acc. Ver: 10.000000
2013-05-30 12:59:14.119 MyApp[30569:907] Acc. Hor: 1414.000000
2013-05-30 12:59:14.131 MyApp[30569:907] -------------------------------------------------------
2013-05-30 12:59:14.138 MyApp[30569:907] URL: http://example.com/json?method=find&lat=51.096827&lng=16.934037&distance=1.000000
2013-05-30 12:59:14.241 MyApp[30569:907] Longitude : 16.933006
2013-05-30 12:59:14.244 MyApp[30569:907] Latitude : 51.096140
2013-05-30 12:59:14.247 MyApp[30569:907] Acc. Ver: 10.000000
2013-05-30 12:59:14.248 MyApp[30569:907] Acc. Hor: 1414.000000
2013-05-30 12:59:14.250 MyApp[30569:907] -------------------------------------------------------
2013-05-30 12:59:14.253 MyApp[30569:907] URL: http://example.com/json?method=find&lat=51.096140&lng=16.933006&distance=1.000000
2013-05-30 12:59:14.256 MyApp[30569:907] Warning: Attempt to present <UINavigationController: 0x1e068fd0> on <HomeViewController: 0x1d572130> while a presentation is in progress!
2013-05-30 12:59:14.260 MyApp[30569:907] Longitude : 16.932491
2013-05-30 12:59:14.262 MyApp[30569:907] Latitude : 51.095797
2013-05-30 12:59:14.263 MyApp[30569:907] Acc. Ver: 10.000000
2013-05-30 12:59:14.264 MyApp[30569:907] Acc. Hor: 1414.000000
2013-05-30 12:59:14.269 MyApp[30569:907] -------------------------------------------------------
2013-05-30 12:59:14.287 MyApp[30569:907] URL: http://example.com/json?method=find&lat=51.095797&lng=16.932491&distance=1.000000
2013-05-30 12:59:14.291 MyApp[30569:907] Warning: Attempt to present <UINavigationController: 0x1d599790> on <HomeViewController: 0x1d572130> while a presentation is in progress!
2013-05-30 12:59:14.298 MyApp[30569:907] Longitude : 16.932234
2013-05-30 12:59:14.301 MyApp[30569:907] Latitude : 51.095625
2013-05-30 12:59:14.302 MyApp[30569:907] Acc. Ver: 10.000000
2013-05-30 12:59:14.303 MyApp[30569:907] Acc. Hor: 1414.000000
2013-05-30 12:59:14.304 MyApp[30569:907] -------------------------------------------------------
2013-05-30 12:59:14.307 MyApp[30569:907] URL: http://example.com/json?method=find&lat=51.095625&lng=16.932234&distance=1.000000
2013-05-30 12:59:14.309 MyApp[30569:907] Warning: Attempt to present <UINavigationController: 0x1e06c930> on <HomeViewController: 0x1d572130> while a presentation is in progress!

As you can see, API is called a few times while it should be called only once. Any idea how to make it better?

Rishil Patel
  • 1,977
  • 3
  • 14
  • 30
Stak
  • 31
  • 1
  • 1
    Two ways to do this, 1) Use a `flag`, check `flag=false` before making url request. After url request is sent set `flag=true`. 2) During view controller initialisation, start getting location updates, store the coords and in `findMe` method just make the URL request with stored coords. – Amar May 30 '13 at 11:35
  • @Amar you can add this comment as answer. – Ishu May 30 '13 at 12:23
  • OK, but why is location accuracy bigger less accurate than before? – Stak May 30 '13 at 12:29
  • The first callback to the delegate usually contains a cached location, it could be that the cached location was high accuracy (50m). You should check the age of the location and discard old ones (>30 second) if you don't want the cached location, see [example here](http://stackoverflow.com/a/8250449/1693173) – progrmr May 30 '13 at 13:17
  • You are saving the best accuracy but you are not saving the best location that you received with the best accuracy. And don't expect the accuracy to stay at the best value 3 times in a row, it might be on the borderline and keep toggling back and forth between two values. When you get the accuracy you need, use that and stop. – progrmr May 30 '13 at 15:32
  • @progrmr but I save the best accuracy and I check with the accuracy of the location. When the accuracy is the same as the accuracy from the previous updated location I use that location and stop updating location. – Stak May 30 '13 at 16:03

3 Answers3

3

Try by setting nil to your locationManagers delegate

_locationManager.delegate = nil;
Bhupesh
  • 2,310
  • 13
  • 33
1

Don't rely on the location manager calling your delegate method a specific number of times. You don't control the location manager, so depending on specific behavior beyond what's documented is always going to cause problems for you. You do control your own code, though, so make it do what you want: if you no longer want location updates, have your delegate method ignore updates when you don't want them, or just set the location manager's delegate to nil.

Caleb
  • 124,013
  • 19
  • 183
  • 272
0

As suggested, adding it as answer.

Two ways to do this,

  1. Use a flag, check flag=false before making url request. After url request is sent set flag=true.
  2. During view controller initialisation, start getting location updates, store the coords and in findMe method just make the URL request with stored coords.
Amar
  • 13,202
  • 7
  • 53
  • 71