ios - CLLocationManager 响应能力

标签 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,我发现在我的 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/

相关文章:

c++ - 优化昂贵函数的调用次数

iPhone GPS 准确度

iphone - 测试 IBOutlet 自动连接或在未连接的 socket 上构建失败

iphone - 接听来电时强制终止应用程序

ios - 在 XCode 8 中重用现有的 Provisioning Profile

android - 如何使用谷歌地图 v2 和 gps 在 android 中绘制实时路线

android - 可以从后台服务而不是 Activity 打开 GPS 吗?

ios - 如何创建从 View Controller 到自身的 Storyboard转场?

c# - 与平面数组相比,.Net 中的简单字典查找速度较慢

java - 获取未包含在各种数组中的值的有效方法是什么?