CLLocationManager可能受其他应用程序的影响吗?

时间:2012-01-20 15:35:14

标签: iphone ios cllocationmanager

我遇到了一个非常奇怪的情况,我使用的应用程序使用CLLocationManager来获取用户的当前位置。我使用的包装类与Apple的CLLocationManager示例代码非常相似。它开始寻找位置,并等待它被给予满足某些标准的位置(时间戳年龄,准确度)。当我在GPS可访问的区域时,一切正常。

现在问题。当我在办公室时,在WiFi连接上,GPS信号似乎很糟糕,我打开我的应用程序,它永远找不到合适的位置。我退出我的应用程序,打开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];
        }
    }
}

2 个答案:

答案 0 :(得分:1)

你为什么使用

self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters

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

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

根据我自己的观察:当向iOS询问具有一定所需精度的位置时,结果可能是任何结果:不太准确(即在GPS接收不良的建筑物中),如期望的那样准确,或者实际上比需要(同一应用程序的另一个应用程序或另一个CLlocationManager对象可能同时要求硬件获得更高的准确性 - 然后所有其他应用程序继承更好的值而无需额外的努力)。

除了上述内容之外,可能会对iOS设备是否正在访问互联网产生影响,因为它是辅助 GPS接收器。如果由于某些其他互联网活动而导致该设备碰巧在线,可能会出现某种辅助数据下载的副作用。不过,最后一个想法是纯粹的推测。

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

这样的东西
self.locationManager.distanceFilter = kCLDistanceFilterNone;

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

答案 1 :(得分:0)

是的,我认为CLLocationManager缓存了一些位置的位置,我尝试了一些东西,比如运行GoogleMaps,找到我的位置,然后运行我的应用程序,它立即找到了我的位置。还尝试了,运行导航应用程序,找到我的位置,立即杀死它,运行其他使用位置的应用程序,所有应用程序几乎可以立即找到该位置的锁定。