CLLocationManager响应 [英] CLLocationManager responsiveness

查看:111
本文介绍了CLLocationManager响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,围绕着设备的GPS和来自它的信息。位置数据准确并且是最新的,这一点很重要。我知道该设备受其GPS和GPS限制的限制,但我想知道是否有任何方法可以调整/改善iPhone GPS的性能,特别是在速度方面。由于位置更新滞后于设备实时位置约3-5秒,因此位置管理器报告的速度也滞后于实时值。就我而言,这太长了。我知道我可以做任何事情,但是有没有人在提高iPhone GPS的响应速度方面取得任何成功?每一点都有所不同。



编辑1:

我的位置管理器在单例类中,



内置SingletonDataController.m:

 静态CLLocationManager *的LocationManager; 
locationManager = [CLLocationManager new];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.headingFilter = kCLHeadingFilterNone; (([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging)||([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)){
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;

if
} else {
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}

[sharedSingleton setLocationManager:locationManager];
[locationManager发布];

内部MapView.m(实际使用位置管理器的位置):

   - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
// setup
[SingletonDataController sharedSingleton ] .locationManager.delegate = self; (([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging)||([[$]
//更多设置
}

- (void)batteryChanged { UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)){
[SingletonDataController sharedSingleton] .locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
} else {
[SingletonDataController sharedSingleton] .locationManager.desiredAccuracy = kCLLocationAccuracyBest;



- (void)viewDidLoad {
// setup
[[NSNotificationCenter defaultCenter]
addObserver:self
选择器:@selector(batteryChanged)
名称:UIDeviceBatteryStateDidChangeNotification
object:nil];
//其他设置
}

数据处理发生在的LocationManager:didUpdateToLocation:fromLocation:。我不相信这里的低效率是滞后的原因。



locationManager:didUpdateToLocation:fromLocation:调用这个方法来更新用户界面:

   - (void)setLabels :( CLLocation *)newLocation fromOldLocation:(CLLocation *)oldLocation { 
//设置速度标签
if(迭代> 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 = @不移动;



//设置平均速度标签
if(迭代> 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发布];
}

//设置已用时间标签
NSInteger秒= [[NSDate date] timeIntervalSinceDate:dataObject.locationManagerStartDate];
NSInteger分钟=秒/ 60;
NSInteger小时=分钟/ 60;

//获得余数
秒%= 60;

NSString * timeString;
NSString * secondsString;
NSString * minutesString;
NSString * hoursString; ((秒秒%60)<10){
secondsString = [[NSString alloc] initWithFormat:@0%i,seconds];

;
} else {
secondsString = [[NSString alloc] initWithFormat:@%i,seconds]; (分钟%60)< 10){
minutesString = [[NSString alloc] initWithFormat:@0%i,minutes];
}


} else {
minutesString = [[NSString alloc] initWithFormat:@%i,minutes]; ((小时%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发布];

$ / code>

使用一些NSDates和NSLogs,我发现执行整个 locationManager:didUpdateToLocation:fromLocation:(不仅仅是标签更新方法)在我的iPhone 4上永远不会超过8毫秒;换句话说,数据处理不是问题。

解决方案

好的,有几件事可以改善你的滞后。首先,始终使用kCLLocationAccuracyBestForNavigation。与kCLLocationAccuracyBest之间没有真正的电池使用差异,它们都以最高速度使用GPS。主要区别在于Apple所做的后期处理。第二,没有必要过滤速度== 0.苹果已经做了这样的过滤:如果你的GPS速度降到某个阈值以下(约4公里/ h),操作系统假定您静止不动,并将所有后续样本替换为相同的位置值。它会这样做,直到它认为你再次移动。我假设他们这样做是为了避免当你静止时在地图上抖动。事实上,对于静止值序列的最后一个实际值,速度已经下降到0,所以如果你按照速度== 0进行过滤,那么你就会丢失一个真实的GPS样本。



不幸的是,他们无法避免过滤并获得真正的GPS采样。我和苹果谈过这件事,他们的回应是他们不会改变这种行为。 kCLLocationAccuracyBestForNavigation不如kCLLocationAccuracyBest进行更积极的过滤,所以最好使用它。

第三,你可能已经这样做了,但是确保你在你的电话上调用了setNeedsDisplay从didUpdateFromLocation:中查看权限,以确保地图实际上被重新绘制。



如果你这么做了,你应该有1秒的滞后时间。如果你想在1秒内改善,你可以尝试使用预测技术。从最后两个位置和给定的速度,您可以计算出下一个位置的可能位置,并且已经显示该位置。我的结果与此有不同。它适用于快速移动,不会突然改变速度,如驾驶汽车。对于步行或骑自行车等较慢的运动而言,它效果不佳。

I have an app that revolves around the device's GPS and the information that comes from it. It is important that the location data be accurate and up-to-date. I know that the device is limited by its GPS and the GPS's limits, but I was wondering if there is anything I can do to tweak/improve the performance of the iPhone GPS, particularly in the speed area. Because location updates lag about 3-5 seconds behind the real-time location of the device, the velocity reported by the location manager also lags that far behind the real-time value. In my case, that is simply too long. I understand that there might not be anything I can do, but has anyone had any success in improving the responsiveness of the iPhone GPS? Every little bit makes a difference.

Edit 1:

My location manager is inside a singleton class, as Apple recommends.

Inside 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];

Inside MapView.m (where the location manager is actually used):

- (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
}

The data handling happens inside locationManager:didUpdateToLocation:fromLocation:. I don't believe that inefficiency here is the cause of the lag.

locationManager:didUpdateToLocation:fromLocation: calls this method to update the 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];
}

With a couple of NSDates and NSLogs I have found that the execution of the entire locationManager:didUpdateToLocation:fromLocation: (not just the label updating method) never takes more than about 8ms on my iPhone 4; in other words, the data handling isn't the problem.

解决方案

OK, a couple of things could improve your lag. First of all, use kCLLocationAccuracyBestForNavigation always. There is no real battery usage difference between that and kCLLocationAccuracyBest, they both use the GPS at top speed. The main difference is in the post-processing that Apple does.

Second, there is no need to filter for speed == 0. Apple already does that filtering: if your speed from the GPS drops below a certain threshold (about 4 km/h), the OS assumes you are standing still, and it substitutes the same location value for all subsequent samples. It does that until it thinks you are moving again. I assume they do that to avoid "jittering" on the map when you are standing still. In fact, speed drops to 0 already for the last real value of a sequence of "standing-still" values, so if you filter on speed == 0 than you are missing one real GPS sample.

Unfortunately, they is no way to avoid that filtering and get real GPS samples. I talked to Apple about it, and their response was that they are not going to change the behaviour. kCLLocationAccuracyBestForNavigation does less aggressive filtering than kCLLocationAccuracyBest, so it's best to use that.

Third, you probably are already doing this, but make sure that you call "setNeedsDisplay" on your view right from the "didUpdateFromLocation:", to make sure that the map is actually redrawn.

If you do all that, you should have a lag of about 1 second. If you want to improve on the 1 second than you can try to use predictive techniques. From the last two locations, and the given speed, you can calculate where the next location is likely to be, and already display that location. I have had mixed results with that. It works well for fast movement that does not change speed suddenly, like driving a car. It works less well for slower movement like walking or biking.

这篇关于CLLocationManager响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆