2012-01-20 23 views
4

我遇到了一个非常奇怪的情况,我有一个使用CLLocationManager获取用户当前位置的应用程序。我正在使用与Apple的CLLocationManager示例代码非常相似的包装类。它开始寻找位置,并等待它获得符合某些标准的位置(时间戳记年龄,准确性)。当我在一个非常全球定位系统的地区时,所有的工作都很好。CLLocationManager可能受其他应用程序影响吗?

现在的问题。当我在我的办公室时,在GPS信号看起来很糟糕的WiFi连接上,我打开我的应用程序,它永远找不到合适的位置。我退出应用程序,打开Foursquare,几乎立即找到附近的地方,导致我认为它已经找到了我的位置。我退出Foursquare,然后重新打开我的应用程序,发现它几乎可以立即找到我的位置。

任何人都可以点亮这里可能发生的事情吗?如果人们认为这会有所帮助,我可以发布一些代码,但这更多的是关于其他应用程序如何对CLLocationManager的功能产生正面或负面影响的一般性问题。理想情况下,我很想知道Foursquare究竟是如何如此迅速地获得位置,以及这会如何导致我的应用突然开始获得一个位置。

编辑:它似乎基于下面的答案,人们已经经历了跨应用程序缓存,这很好。然而,这并不能解释为什么Foursquare会获得一个位置,而我的应用只能在使用Foursquare之后才能获得。下面是我的CLLocationManager代码,希望有人能找到一些确凿的证据:

- (void) lazyInit { 
    if (!self.locationManager) { 
     self.locationManager = [[CLLocationManager alloc] init]; 
     self.locationManager.delegate = self; 
     self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; 
     self.reverseGeocoder = [[WPGeocodingService alloc] initWithDelegate:self]; 
     self.locationAndPlacemark = NO; 
    } 
} 

- (void) getCurrentLocation { 
    [self lazyInit]; 
    self.recentLocation = nil; 
    [self performSelector:@selector(timeoutLocationFetch) withObject:nil afterDelay:kLocationFetchTimeout]; 
    [self.locationManager startUpdatingLocation]; 
} 

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { 
    NSLog(@"LocationService:update: <%f,%f> Accuracy: %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude, 
      newLocation.horizontalAccuracy); 

    // test the age of the location measurement to determine if the measurement is cached 
    // in most cases you will not want to rely on cached measurements 
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow]; 
    if (locationAge > 5.0) return; 

    // test that the horizontal accuracy does not indicate an invalid measurement 
    if (newLocation.horizontalAccuracy < 0) return; 

    // test the measurement to see if it is more accurate than the previous measurement 
    if (self.recentLocation == nil || self.recentLocation.horizontalAccuracy > newLocation.horizontalAccuracy) { 
     // store the location as the "best effort" 
     self.recentLocation = newLocation; 
     // test the measurement to see if it meets the desired accuracy 
     // 
     // IMPORTANT!!! kCLLocationAccuracyBest should not be used for comparison with location coordinate or altitidue 
     // accuracy because it is a negative value. Instead, compare against some predetermined "real" measure of 
     // acceptable accuracy, or depend on the timeout to stop updating. This sample depends on the timeout. 
     // 
     if (newLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) { 
      // we have a measurement that meets our requirements, so we can stop updating the location 
      // 
      // IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible. 
      // 
      [self.locationManager stopUpdatingLocation]; 
      // we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary 
      [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeoutLocationFetch) object:nil]; 

      if ([self.delegate respondsToSelector:@selector(locationService:didReceiveLocation:)]) { 
       [self.delegate locationService:self didReceiveLocation:self.recentLocation]; 
      } 
     } 
    }  
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 
    NSLog(@"LocationService:error: %@", [error description]); 
    if ([error code] != kCLErrorLocationUnknown) { 
     [self.locationManager stopUpdatingLocation]; 
     if ([self.delegate respondsToSelector:@selector(locationService:didFailWithError:)]) { 
      [self.delegate locationService:self didFailWithError:error]; 
     } 
    } 
} 

- (void) timeoutLocationFetch { 
    NSLog(@"LocationService:timeout"); 
    [self.locationManager stopUpdatingLocation]; 
    if (self.recentLocation && [self.delegate respondsToSelector:@selector(locationService:didReceiveLocation:)]) { 
     if ([self.delegate respondsToSelector:@selector(locationService:didReceiveLocation:)]) { 
      [self.delegate locationService:self didReceiveLocation:self.recentLocation]; 
     } 
    } else { 
     NSError* error = [NSError errorWithDomain:@"Location Error" code:0 userInfo: 
          [NSDictionary dictionaryWithObject:@"The application could not determine your location." forKey:NSLocalizedDescriptionKey]]; 
     if ([self.delegate respondsToSelector:@selector(locationService:didFailWithError:)]) { 
      [self.delegate locationService:self didFailWithError:error]; 
     } 
    } 
} 
+0

我们很多人都想知道同样的事情..... – KevinDTimm

+0

在缓存方面,或者Foursquare如何收集位置坐标? – nickbona

+0

我已经看到了一些有趣的行为:在启动时收集不与(例如)谷歌地图嬉戏的地点。虽然他们(似乎)立即获取信息,但我的应用程序似乎并未尽快获取位置更新。在我的应用程序之前运行地图(例如)提高了我的应用程序的性能:(这看起来不正确 – KevinDTimm

回答

1

你为什么要使用

self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters 

,而不是kCLLocationAccuracyBest?当然,如果没有将水平精度与此相比较,就像你自己注意到的那样,负数常数 - 但是一些合理的其他数值(比如100.0m)代替。你有没有尝试过它是否有所作为?

期望的精度控制了多少努力投入位置采集(对于更高的值,GPS甚至没有打开,因为您可以检查Xcode/Instruments/EnergyDiagnostics)。较少的努力会导致准确性降低和/或获得职位的时间更多。这听起来不合理吗?

根据我自己的观察:当向iOS询问具有某种期望精度的位置时,结果可能是任何事情:较不准确(即在具有较差的GPS接收的建筑物中),精度要求高或实际上更准确(另一个应用程序或同一应用程序的另一个CLlocationManager对象可能会同时要求硬件提供更高的准确性 - 那么所有其他应用程序都会继承更好的值,而无需额外的工作)。

除了上面,可能有所作为的iOS设备是否您正在访问互联网,因为它是一个辅助 GPS接收器。如果由于某些其他互联网活动而使设备发生在线,可能会出现一些辅助数据下载的副作用。不过,这最后的想法是纯粹的猜测。

还有一件事: 如果我没有在你的代码中忽略它,那么你还没有定义一个距离过滤器。尝试类似

self.locationManager.distanceFilter = kCLDistanceFilterNone; 

确保您获得尽可能多的更新。

+0

您将此标记为正确的答案,但没有说明三个建议中的哪一个是重要部分。我可以认为它是所需的准确性设置? – Ant

0

是的,我认为CLLocationManager缓存在一定程度上,我尝试了一些东西,比如运行谷歌地图的位置,我的位置被发现,然后跑我的应用程序,它立即找到我的位置。还尝试过,运行导航应用程序,找到我的位置,立即杀死它,运行其他使用位置的应用程序,所有应用程序几乎可以在瞬间找到该位置的锁。

相关问题