优化CLLocationManager / CoreLocation在iPhone上更快地检索数据点 [英] Optimizing CLLocationManager/CoreLocation to retrieve data points faster on the iPhone

查看:74
本文介绍了优化CLLocationManager / CoreLocation在iPhone上更快地检索数据点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用CoreLocation + CLLocationManager,以便将用户当前位置与N个其他位置进行比较。我面临的问题是我处理的位置相互靠近的城市地区,所以我需要指出用户的位置准确的设备允许,而不牺牲太多的时间。我的计算是准确的,问题是,它需要太长时间来收集10个样本。我将在下面粘贴我的过滤器/准确度相应的代码。如果任何人都可以评论我如何加快速度,这将是巨大的。直到我加快速度,它在我的应用程序是无用的,因为它目前需要大约3-4分钟来收集信息,这是我的目标受众特征不接受的时间。



代码看起来像这样:

  [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; 
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if(newLocation.horizo​​ntalAccuracy> 0.0 f&&
newLocation.horizo​​ntalAccuracy< 120.0f){//大约120米的精度,我们可以调整。

[myLocs addObject:newLocation];
}

感谢任何优化技巧加快速度。

解决方案

我在iPhone上也有很多问题CLLocationManager。
从不同的应用程序,尝试和错误这是我想出了;



1)使用singleton类的locationManager,只有一个实例,请按照以下示例:



Apple's LocateMe示例



Tweetero: http://tweetero.googlecode.com/svn/trunk



I'你认为你只能有一个位置管理器运行,在iPhone中只有一个GPS芯片,因此,如果你启动多个位置管理器对象,他们会冲突,你会从GPS位置管理器错误,说它不能更新。 / p>

2)非常小心如何更新locationManager.desiredAccuracy和
locationManager.distanceFilter
按照Apple的代码中的示例,在FlipsideViewController中:

  [MyCLController sharedInstance] .locationManager.desiredAccuracy = accuracyToSet; 
[MyCLController sharedInstance] .locationManager.distanceFilter = filterToSet;

此方法可行,并且不会导致错误。如果你在主委托循环中更新desiredAccuracy或
distanceFilter:

   - (void)locationManager:(CLLocationManager * )manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 

核心位置可能会抱怨它不能更新值,并给你错误。
此外,只使用Apple提供的desiredAccuracy的常量,没有其他的
;
kCLLocationAccuracyBest,kCLLocationAccuracyNearestTenMeters,
kCLLocationAccuracyHundredMeters,kCLLocationAccuracyKilometer,
kCLLocationAccuracyThreeKilometers



使用其他值可能会导致locationManager发生错误。
对于distanceFilter你可以使用任何值,但要注意的是人们已经说明它有问题,
主要的值默认是:-1 =最好,我使用10.0,它似乎确定。 / p>

3)要强制一个新的更新,调用startUpdates方法,如在Tweetero,这迫使
locationManager做它的东西,它应该尝试,新值。



4)核心位置委托例程很难获得准确的更新。
当你的应用程序第一次初始化你可以关闭准确度1000米或更多,因此
一次尝试不会这样做。初始化后的三次尝试通常会让你
到47左右,这是好的。记住,每次连续的尝试都是
,需要更长的时间来提高你的准确性,因此它很快就变得昂贵。
这是你需要做的:
只有当它是最近时才采用一个新值AND
如果新位置有更好的准确性,新的位置OR
如果新的位置具有< 50米取新位置OR
如果尝试次数超过3或5, 150米AND
的位置已更改,那么这是一个新的位置,设备移动所以采取这
值,即使它的精度更差。
这是我的位置代码:

   - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation :( CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{
locationDenied = NO;

if(![[NSUserDefaults standardUserDefaults] boolForKey:@UseLocations])
{
[self stopAllUpdates];
return;
}

NSDate * eventDate = newLocation.timestamp;
NSTimeInterval howRecent = abs([eventDate timeIntervalSinceNow]);
attempts ++;

if((newLocation.coordinate.latitude!= oldLocation.coordinate.latitude)&&(newLocation.coordinate.longitude!= oldLocation.coordinate.longitude))
locationChanged = YES ;
else
locationChanged = NO;

#ifdef __i386__
//为模拟器执行此操作,因为位置总是返回Cupertino
if(howRecent< 5.0)
#else
//这里是操作理论
//如果值是最近的AND
//如果新位置具有稍好的准确性,取新的位置OR
//如果新位置具有精确度; 50米采取新位置OR
//如果尝试最大(3 -5)AND精度< 150并且位置已经改变,那么这必须是一个新的位置,并且设备移动
//所以采取这个新的值,即使它的准确性可能更糟糕
if((howRecent< 5.0)& &((newLocation.horizo​​ntalAccuracy<(oldLocation.horizo​​ntalAccuracy - 10.0))||(newLocation.horizo​​ntalAccuracy <50.0)
||(attempt> = attempt)&(newLocation.horizo​​ntalAccuracy< ; = 150.0)&&& amp; locationChanged)))
#endif
{
attempts = 0;
latitude = newLocation.coordinate.latitude;
longitude = newLocation.coordinate.longitude;
[currentLocation release];
currentLocation = [newLocation retain];
goodLocation = YES;

[[NSNotificationCenter defaultCenter] postNotificationName:@UpdateLocationNotificationobject:nil];

if(oldLocation!= nil){
distanceMoved = [newLocation getDistanceFrom:oldLocation];
currentSpeed = newLocation.speed;
distanceTimeDelta = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
}
}
//将更新发送给我们的委托
[self.delegate newLocationUpdate:currentLocation];
}

如果你有一个iPhone 3GS获取标题更新很容易,代码与上述模块相同:

  //这是标题或指南针值
- :(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
if(newHeading.headingAccuracy> 0)
{
[newHeading retain]
// headingType = True for True North或NO for Magnetic North
if(headingType){
currentHeading = newHeading.trueHeading;
} else {
currentHeading = newHeading.magneticHeading;
}

goodHeading = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:@UpdateHeadingNotificationobject:nil];

}
}

希望这有助于人们! p>

I'm currently using CoreLocation + CLLocationManager in order to compare a users current location to N amount of other locations. The problem I'm facing is I'm dealing with urban areas where locations are close to each other, so I need to pin point the location of the user as accurately as the device allows without sacrificing too much time. My calculations are darn accurate, the problem is, it takes far too long to collect 10 samples. I'll paste my filters/accuracy respective code below. If anyone can comment on how I can speed this up, that would be great. Until I speed it up, it's rather useless in my app as it currently takes around 3-4 minutes to gather info, a duration that's not accept by my target demographic.

Code looks something like this:

[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    if (newLocation.horizontalAccuracy > 0.0f &&
        newLocation.horizontalAccuracy < 120.0f) { // roughly an accuracy of 120 meters, we can adjust this.

    [myLocs addObject:newLocation];
}

Thanks for any optimization tricks to speed this up.

解决方案

I've had lots of issues with CLLocationManager on the iPhone also. From different Apps, and trial and error this is what I've figured out;

1) Use a singleton class for the locationManager, ONLY ONE Instance, follow the examples in:

Apple's LocateMe example

Tweetero : http://tweetero.googlecode.com/svn/trunk

I'm thinking you can only have one location manager running, there's only one GPS chip in the iPhone, thus if you launch multiple location manager object's they'll conflict, and you get errors from the GPS location manager stating it can't update.

2) Be extremely careful how you update the locationManager.desiredAccuracy and locationManager.distanceFilter Follow the example in Apple's code for this in the FlipsideViewController:

[MyCLController sharedInstance].locationManager.desiredAccuracy = accuracyToSet;
[MyCLController sharedInstance].locationManager.distanceFilter = filterToSet;

This approach works, and causes no errors. If you update the desiredAccuracy or distanceFilter in the main delegate loop:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation  fromLocation:(CLLocation *)oldLocation

Core Location will likely complain that it can't update the values, and give you errors. Also, only use the constants for the desiredAccuracy supplied by Apple, and no others, thus; kCLLocationAccuracyBest, kCLLocationAccuracyNearestTenMeters, kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer, kCLLocationAccuracyThreeKilometers

Use of other values might give you errors from locationManager. For distanceFilter you can use any value, but be aware people have stated it has issues, the main value to default to is: -1 = Best, I've used 10.0 and it seems OK.

3) To force a new update, call the startUpdates method like in Tweetero, this forces locationManager to do it's thing, and it should try and get you a new value.

4) The core location delegate routine is tricky to get accurate updates out of. When your App first initializes you can be off in accuracy by 1000 meters or more, thus one attempt is not going to do it. Three attempts after initialization usually gets you to within 47 or so meters which is good. Remember that each successive attempt is going to take longer and longer to improve your accuracy, thus it gets expensive quickly. This is what you need to do: Take a new value only if it is recent AND If the new location has slightly better accuracy take the new location OR If the new location has an accuracy < 50 meters take the new location OR If the number of attempts has exceeded 3 or 5 AND the accuracy < 150 meters AND the location has CHANGED, then this is a new location and the device moved so take this value even if it's accuracy is worse. Here's my Location code to do this:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation  *)newLocation  fromLocation:(CLLocation *)oldLocation
{
    locationDenied = NO;

    if(![[NSUserDefaults standardUserDefaults] boolForKey:@"UseLocations"])
    {
        [self stopAllUpdates];
        return;
    }

    NSDate* eventDate = newLocation.timestamp;
    NSTimeInterval howRecent = abs([eventDate timeIntervalSinceNow]);
    attempts++;

    if((newLocation.coordinate.latitude != oldLocation.coordinate.latitude) && (newLocation.coordinate.longitude != oldLocation.coordinate.longitude))
        locationChanged = YES;
        else
            locationChanged = NO;

    #ifdef __i386__
            //Do this for the simulator since location always returns Cupertino
            if (howRecent < 5.0)
    #else
                // Here's the theory of operation
                // If the value is recent AND
                // If the new location has slightly better accuracy take the new location OR
                // If the new location has an accuracy < 50 meters take the new location OR
                // If the attempts is maxed (3 -5) AND the accuracy < 150 AND the location has changed, then this must be a new location and the device moved
                // so take this new value even though it's accuracy might be worse
                if ((howRecent < 5.0) && ( (newLocation.horizontalAccuracy < (oldLocation.horizontalAccuracy - 10.0)) || (newLocation.horizontalAccuracy < 50.0)
                                          || ((attempts >= attempt) && (newLocation.horizontalAccuracy <= 150.0) && locationChanged)))
    #endif
                {
                    attempts = 0;
                    latitude = newLocation.coordinate.latitude;
                    longitude = newLocation.coordinate.longitude;
                    [currentLocation release];
                    currentLocation = [newLocation retain];
                    goodLocation = YES;

                    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateLocationNotification" object: nil];

                    if (oldLocation != nil) {
                        distanceMoved = [newLocation getDistanceFrom:oldLocation];
                        currentSpeed = newLocation.speed;
                        distanceTimeDelta = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
                    }
                }
    // Send the update to our delegate
    [self.delegate newLocationUpdate:currentLocation];
}

If you have a iPhone 3GS getting Heading updates is a lot easier, here's the code in the same module as above:

//This is the Heading or Compass values
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    if (newHeading.headingAccuracy > 0)
    {
        [newHeading retain];
        // headingType = YES for True North or NO for Magnetic North
        if(headingType) {
            currentHeading = newHeading.trueHeading;
        } else {
            currentHeading = newHeading.magneticHeading;
        }

        goodHeading = YES;
        [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateHeadingNotification" object: nil];

    }
}

Hope this helps people!

这篇关于优化CLLocationManager / CoreLocation在iPhone上更快地检索数据点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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