title: CLLocationManager responsiveness
body: <p>I have an app that revolves around the device's GPS and the information that comes from it. It is important that the location data be accurate and up-to-date. I know that the device is limited by its GPS and the GPS's limits, but I was wondering if there is anything I can do to tweak/improve the performance of the iPhone GPS, particularly in the speed area. Because location updates lag about 3-5 seconds behind the real-time location of the device, the velocity reported by the location manager also lags that far behind the real-time value. In my case, that is simply too long. I understand that there might not be anything I can do, but has anyone had any success in improving the responsiveness of the iPhone GPS? Every little bit makes a difference.</p>
  
  <p>Edit 1:</p>
  
  <p>My location manager is inside a singleton class, as Apple recommends.</p>
  
  <p>Inside SingletonDataController.m:</p>
  
  <pre><code>static CLLocationManager* locationManager;
  locationManager = [CLLocationManager new];
  locationManager.distanceFilter = kCLDistanceFilterNone;
  locationManager.headingFilter = kCLHeadingFilterNone;
  
  if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) {
      locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
  } else {
      locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  }
  
  [sharedSingleton setLocationManager:locationManager];
  [locationManager release];
  </code></pre>
  
  <p>Inside MapView.m (where the location manager is actually used):</p>
  
  <pre><code>- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil {
      //setup
      [SingletonDataController sharedSingleton].locationManager.delegate = self;
      //more setup
  }
  
  - (void)batteryChanged {
      if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) {
          [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
      } else {
          [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBest;
      }
  }
  
  - (void)viewDidLoad {
      //setup
      [[NSNotificationCenter defaultCenter]
        addObserver:self 
           selector:@selector(batteryChanged) 
               name:UIDeviceBatteryStateDidChangeNotification 
             object:nil];
      //other setup
  }
  </code></pre>
  
  <p>The data handling happens inside <code>locationManager:didUpdateToLocation:fromLocation:</code>. I don't believe that inefficiency here is the cause of the lag.</p>
  
  <p><code>locationManager:didUpdateToLocation:fromLocation:</code> calls this method to update the UI:</p>
  
  <pre><code>- (void)setLabels:(CLLocation*)newLocation fromOldLocation:(CLLocation*)oldLocation {
      //set speed label
      if(iterations &gt; 0) {
          if(currentSpeed &gt; keyStopSpeedFilter) {
              if(isFollowing) {
                  [mapViewGlobal setRegion:MKCoordinateRegionMake([newLocation coordinate], mapViewGlobal.region.span)];
              }
  
              NSString* currentSpeedString;
              if(isCustomary) {
                  currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (currentSpeed * 2.23693629f)];
              } else {
                  currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (currentSpeed * 3.6f)];
              }
  
              [speedLabel setText:currentSpeedString];
              [currentSpeedString release];
          } else {
              speedLabel.text = @"Not moving";
          }
      }
  
      //set average speed label
      if(iterations &gt; 4 &amp;&amp; movementIterations &gt; 2) {
          NSString* averageSpeedString;
          if(isCustomary) {
              averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (float)((speedAverages / (long double)movementIterations) * 2.23693629f)];
          } else {
              averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (float)((speedAverages / (long double)movementIterations) * 3.6f)];
          }
          [averageSpeedLabel setText:averageSpeedString];
          [averageSpeedString release];
      }
  
      //set elapsed time label
      NSInteger seconds = [[NSDate date] timeIntervalSinceDate:dataObject.locationManagerStartDate];
      NSInteger minutes = seconds / 60;
      NSInteger hours = minutes / 60;
  
      //get remainder
      seconds %= 60;
  
      NSString* timeString;
      NSString* secondsString;
      NSString* minutesString;
      NSString* hoursString;
  
      if((seconds % 60) &lt; 10) {
          secondsString = [[NSString alloc] initWithFormat:@"0%i", seconds];
      } else {
          secondsString = [[NSString alloc] initWithFormat:@"%i", seconds];
      }
  
      if((minutes % 60) &lt; 10) {
          minutesString = [[NSString alloc] initWithFormat:@"0%i", minutes];
      } else {
          minutesString = [[NSString alloc] initWithFormat:@"%i", minutes];
      }
  
      if((hours % 60) &lt; 10) {
          hoursString = [[NSString alloc] initWithFormat:@"0%i", hours];
      } else {
          hoursString = [[NSString alloc] initWithFormat:@"%i", hours];
      }
  
      timeString = [[NSString alloc] initWithFormat:@"%@:%@:%@", hoursString, minutesString, secondsString];
  
      [elapsedTimeLabel setText:timeString];
  
      [timeString release], timeString = nil;
      [secondsString release], secondsString = nil;
      [minutesString release], minutesString = nil;
      [hoursString release], hoursString = nil;
  
      NSString* totalDistanceString;
      if(isCustomary) {
          totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f mi", (float)distance * 0.000621371192f];
      } else {
          totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f km", (float)distance / 1000.0f];
      }
      [customTopBar setTitle:totalDistanceString];
      [totalDistanceString release];
  }
  </code></pre>
  
  <p>With a couple of NSDates and NSLogs I have found that the execution of the entire <code>locationManager:didUpdateToLocation:fromLocation:</code> (not just the label updating method) never takes more than about 8ms on my iPhone 4; in other words, the data handling isn't the problem.</p>