【问题标题】:Optimizing CLLocationManager/CoreLocation to retrieve data points faster on the iPhone优化 CLLocationManager/CoreLocation 以在 iPhone 上更快地检索数据点
【发布时间】:2010-11-08 01:10:25
【问题描述】:

我目前正在使用 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.horizontalAccuracy > 0.0f &&
        newLocation.horizontalAccuracy < 120.0f) { // roughly an accuracy of 120 meters, we can adjust this.

    [myLocs addObject:newLocation];
}

感谢您提供任何优化技巧来加快速度。

【问题讨论】:

    标签: iphone cocoa-touch core-location


    【解决方案1】:

    iPhone 上的 CLLocationManager 也有很多问题。 从不同的应用程序中,经过反复试验,这是我发现的;

    1) 对locationManager使用单例类,只有一个实例,参照以下示例:

    Apple 的 LocateMe 示例

    推特罗:http://tweetero.googlecode.com/svn/trunk

    我认为您只能运行一个位置管理器,iPhone 中只有一个 GPS 芯片,因此如果您启动多个位置管理器对象,它们会发生冲突,并且您会从 GPS 位置管理器中收到错误,说明它可以不更新。

    2) 更新locationManager.desiredAccuracylocationManager.distanceFilter

    在 FlipsideViewController 中遵循 Apple 代码中的示例:

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

    这种方法有效,不会导致错误。如果您更新所需的Accuracy 或 主委托循环中的 distanceFilter:

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

    Core Location 可能会抱怨它无法更新值,并给您错误。 此外,仅使用 Apple 提供的 desiredAccuracy 的常量,不要使用其他常量, 因此;

    kCLLocationAccuracyBest,kCLLocationAccuracyNearestTenMeters,
    kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer,
    kCLLocationAccuracyThreeKilometers

    使用其他值可能会给您带来来自 locationManager 的错误。 对于distanceFilter,您可以使用任何值,但请注意人们已经表示它有问题, 默认的主要值是:-1 = 最佳,我用过 10.0,看起来还可以。

    3) 要强制更新,请像在 Tweetero 中一样调用 startUpdates 方法,这会强制 locationManager 来做这件事,它应该尝试给你一个新的价值。

    4) 核心位置委托例程很难获得准确的更新。 当您的应用程序首次初始化时,您的精度可能会相差 1000 米或更多,因此 一次尝试是行不通的。初始化后的三次尝试通常会让你 到 47 米左右,这很好。请记住,每次连续的尝试都在进行 花费越来越长的时间来提高您的准确性,因此它很快就会变得昂贵。 这是你需要做的: 仅当它是最近的 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__
                //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];
    }
    

    如果您有 iPhone 3GS,获取标题更新要容易得多,下面是与上述相同模块中的代码:

    //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];
    
        }
    }
    

    希望这对人们有所帮助!

    【讨论】:

    • 很棒的代码。但正如以下答案所述,didUpdateToLocation: 触发可能需要很长时间。我已经尝试过,但无论如何,当我在里面时,我看到更新相当缓慢 - 有时需要一分钟或更长时间。但是,如果我切换到 Maps.app,它会立即找到我的位置。我希望我们可以通过 API 获得与 MapKit 相同的即时准确性。
    • 我想知道为什么它会在用户默认值中检查“UseLocations”?这个值是操作系统自动设置的吗?
    • 很棒的代码。当你设置 locationChanged = YES 时,if 语句应该使用 ||代替 &&。如果纬度或经度发生了变化,则位置已更改。
    【解决方案2】:

    didUpdateToLocation 仅在用户移动位置时更新。这可能是零星的,我相信你已经注意到了。 CCLocationManager 不会定期发送更新,而是在用户移动时发送更新,或者它会提高其准确性。当我静止不动并启动一个应用程序时,我通常会收到大约三个更新,然后有一段时间什么都没有。谷歌地图做了类似的事情,随着准确性的提高,显示一个环与点。我建议等到您达到所需的准确度 (

    如果您习惯了“普通”GPS,它会发送更新,并且它会不断提高其准确性,恐怕 iPhone 不是为此而设计的。

    或者,您可以使用 MapKit API,向用户显示地图及其位置,并在他们认为位置足够准确时允许他们“接受”。我注意到有时我会得到一个精确定位,然后 30 秒后它会将我移动到离我实际位置近 50 米的位置。

    【讨论】:

      【解决方案3】:

      我为此写了一个 GIT repo,你可以免费使用https://github.com/xelvenone/M6GPSLocationManager

      • 如果结果准确度优于可接受的准确度,我们就完成了
      • 如果我们获得了有关发生率的更新,我们将等待 maximumWaitTimeForBetterResult 以获得更好的结果,- 如果没有发生,我们就完成并采用最好的结果
      • 如果我们不断获得超过 maximumAttempts 的更新,我们会采用最好的更新(可能无论如何我们都在移动)
      • 如果我们在 30 秒内没有获得任何其他更新,我们就完成了(可能不会有任何其他更新)

      代码

      - (void)scopeToCurrentLocationWithAcceptableAccuracy:(CLLocationAccuracy)acceptableAccuracy
                    maximumWaitTimeForBetterResult:(NSTimeInterval)maximumWaitTimeForBetterResult
                                   maximumAttempts:(NSInteger)maximumAttempts
                                      onCompletion:(M6GPSLocationManagerCompletion)completion;
      

      【讨论】:

        猜你喜欢
        • 2016-03-18
        • 1970-01-01
        • 2021-09-13
        • 1970-01-01
        • 1970-01-01
        • 2021-10-08
        • 2022-09-28
        • 1970-01-01
        • 2021-11-10
        相关资源
        最近更新 更多