我有一个围绕设备的 GPS 和来自它的信息的应用程序。位置数据必须准确且是最新的,这一点很重要。我知道该设备受其 GPS 和 GPS 限制的限制,但我想知道我是否可以做些什么来调整/改进 iPhone GPS 的性能,尤其是在速度方面。由于位置更新滞后于设备的实时位置大约 3-5 秒,因此位置管理器报告的速度也远远落后于实时值。就我而言,那太长了。我知道我可能无能为力,但有没有人在提高 iPhone GPS 的响应能力方面取得成功?每一点点都会产生影响。
编辑 1:
按照 Apple 的建议,我的位置管理器位于单例类中。
在 SingletonDataController.m 中:
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];
在 MapView.m 内部(实际使用位置管理器的地方):
- (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
}
数据处理发生在 locationManager:didUpdateToLocation:fromLocation:
中。我不认为这里的低效率是延迟的原因。
locationManager:didUpdateToLocation:fromLocation:
调用此方法更新 UI:
- (void)setLabels:(CLLocation*)newLocation fromOldLocation:(CLLocation*)oldLocation {
//set speed label
if(iterations > 0) {
if(currentSpeed > 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 > 4 && movementIterations > 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) < 10) {
secondsString = [[NSString alloc] initWithFormat:@"0%i", seconds];
} else {
secondsString = [[NSString alloc] initWithFormat:@"%i", seconds];
}
if((minutes % 60) < 10) {
minutesString = [[NSString alloc] initWithFormat:@"0%i", minutes];
} else {
minutesString = [[NSString alloc] initWithFormat:@"%i", minutes];
}
if((hours % 60) < 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];
}
通过一些 NSDates 和 NSLogs,我发现在我的 iPhone 4 上,整个 locationManager:didUpdateToLocation:fromLocation:
(不仅仅是标签更新方法)的执行时间从不超过 8ms ;换句话说,数据处理不是问题。
最佳答案
好的,有几件事可以改善您的延迟。首先,始终使用 kCLLocationAccuracyBestForNavigation。那和 kCLLocationAccuracyBest 之间没有真正的电池使用差异,它们都以最快的速度使用 GPS。主要区别在于 Apple 所做的后处理。
其次,无需针对速度 == 0 进行过滤。Apple 已经进行了过滤:如果您从 GPS 获取的速度低于某个阈值(约 4 公里/小时),操作系统会假定您静止不动,并且它将相同的位置值替换为所有后续样本。它会这样做,直到它认为你又要移动了。我认为他们这样做是为了避免您站着不动时在 map 上“抖动”。事实上,对于一系列“静止”值的最后一个真实值,速度已经下降到 0,因此如果您过滤速度 == 0,那么您将错过一个真实的 GPS 样本。
不幸的是,他们无法避免这种过滤并获得真实的 GPS 样本。我和 Apple 谈过这件事,他们的回应是他们不会改变这种行为。 kCLLocationAccuracyBestForNavigation 的过滤不如 kCLLocationAccuracyBest 激进,因此最好使用它。
第三,您可能已经在执行此操作,但请确保直接从“didUpdateFromLocation:”在您的 View 上调用“setNeedsDisplay”,以确保 map 确实已重绘。
如果你这样做了,你应该会有大约 1 秒的延迟。如果你想提高 1 秒,你可以尝试使用预测技术。根据最后两个位置和给定的速度,您可以计算出下一个位置可能所在的位置,并已显示该位置。我的结果好坏参半。它适用于不会突然改变速度的快速运动,例如驾驶汽车。它不太适用于较慢的运动,如步行或骑自行车。
关于ios - CLLocationManager 响应能力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9746675/