CLLocationManager响应

时间:2012-03-17 02:15:50

标签: ios performance gps core-location cllocationmanager

我有一个应用程序,围绕设备的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,我发现整个locationManager:didUpdateToLocation:fromLocation:(不仅仅是标签更新方法)的执行在我的iPhone 4上的持续时间不会超过8毫秒;换句话说,数据处理不是问题。

3 个答案:

答案 0 :(得分:27)

好的,有几件事可以改善你的滞后。首先,始终使用kCLLocationAccuracyBestForNavigation。它与kCLLocationAccuracyBest之间没有真正的电池使用差异,它们都以最高速度使用GPS。主要区别在于Apple的后处理。

其次,没有必要过滤速度== 0.苹果已经进行过滤:如果你的GPS速度低于某个阈值(约4公里/小时),操作系统假设你站着不动,并且它为所有后续样本替换相同的位置值。这样做直到它认为你再次移动。我假设他们这样做是为了避免当你站着不动时在地图上“抖动”。实际上,对于一系列“静止”值的最后一个实际值,速度已降至0,因此如果您在速度= = 0时过滤而不是丢失一个真实的GPS样本。

不幸的是,他们无法避免过滤并获得真实的GPS样本。我和Apple谈过这件事,他们的反应是他们不会改变这种行为。 kCLLocationAccuracyBestForNavigation执行的过滤比kCLLocationAccuracyBest更少,因此最好使用它。

第三,你可能已经这样做了,但要确保你在“didUpdateFromLocation:”的视图上调用“setNeedsDisplay”,以确保实际重绘了地图。

如果你做了所有这些,你应该有大约1秒的滞后。如果你想在1秒内改进,你可以尝试使用预测技术。从最后两个位置和给定的速度,您可以计算下一个位置可能的位置,并且已经显示该位置。我的结果好坏参半。它适用于快速移动,不会像驾驶汽车那样突然改变速度。对于像步行或骑自行车这样的慢速运动,它的效果较差。

答案 1 :(得分:6)

在iPhone中,我们可以通过两种方法配置位置服务 -

  1. 使用Standard Location Services,即卫星GPS,为您提供更准确的数据。
  2. 使用使用A-GPS的Significant Location Changes或通过wi-fi获取定位数据较少的位置。
  3. 我们可以通过这两种方法中的任何一种来配置位置服务,但这取决于应用程序的要求。 如果应用是navigation applocation tracking app,那么我们应该使用Standard Location Services,但在使用标准服务之前,我们要记住,如果您想要更准确的数据,那么您必须使用{{ 1}}。 如果应用不需要更频繁地更新位置以及battery consume more quickly,那么我们应accuracy doesn't matter,因为与标准位置服务相比,Significant Location Changes会消耗。

    标准位置服务使用save a lot of batterydesiredAccuracy值来确定是否以及何时投放活动。

    distanceFilter是您可以定义GPS硬件所需精度的参数。它使用一些预定义的常量作为 -

    desiredAccuracy

    kCLLocationAccuracyBestForNavigation kCLLocationAccuracyBest kCLLocationAccuracyNearestTenMeters kCLLocationAccuracyHundredMeters kCLLocationAccuracyKilometer kCLLocationAccuracyThreeKilometers 是您必须定义距离的参数,表示您要求GPS硬件发送位置更新的距离差距。

    在你的情况下,你正在处理速度参数,所以我猜它的东西与导航有关。所以你应该使用distanceFilter。我认为你也是这样做的,但你所面临的问题是位置更新之间的滞后。在这里,我建议您将Standard Location ServicesdesiredAccuracy值修改为此 -

    [locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters]; [locationManager setDistanceFilter:10.0f];

    通过设置值,如果您正在驾驶,您将在不到1秒内获得位置更新。

    还有一件事需要记住,当您获得位置更新时,应检查其distanceFilter值以忽略旧的位置更新。这是因为当您通过拨打timestamp启动locationManager时,您获得的第一个位置可能是您的旧位置。此外,您还必须检查startUpdatingLocation值,因为您获得的前几个位置更新始终不准确,并且可能具有1000或更多的准确性,而您并不需要。因此,您必须检查其值以忽略不准确的位置更新。

    horizontalAccuracy

答案 2 :(得分:1)

除了如何使用核心位置的其他好例子之外,还要记住从Kalman Filtering的不太好的传感器(例如智能手机定位服务)获得良好运动学结果的一般技术。 / p>

这是一个很多数学,测试和调整,但它确实让你得到用户认为比传感器提供的简单数据更好的结果。

这是用于航空电子设备和雷达处理系统的东西。