2

在根据当前位置检查本地数据、关闭应用程序、稍微移动并再次打开应用程序时,我试图克服 didUpdateToLocation 有时失败的问题。发生的情况是用户访问一个地方,检查列表,去另一个地方,并且列表被更新但使用旧的位置数据。

我想确保我有一个新的新位置。

这段代码有什么问题?

double aa,bb,cc;

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
        //old data? retry.
    aa=[newLocation.timestamp timeIntervalSinceReferenceDate];
    bb=[NSDate timeIntervalSinceReferenceDate];
    cc=bb-aa;   //must be <60 - minute-fresh
    if (cc>60) {
        [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
        [manager startUpdatingLocation];    //only stop if new reliable pos fetched.
        return;
    }
...handle position
}

症状是 cc 在应用程序启动时大约为 1200 秒,然后在每次重试时增加几秒钟。

我试过-[newLocation.timestamp timeIntervalSinceNow]了,同样,每次重试都会增加几秒钟。在某一时刻,间隔约为 2400。

如果可能会影响它,我正在使用 FilterNone 和 AccuracyBest。

我对替代代码解决方案持开放态度,以确保你有一个新的职位。

4

3 回答 3

2

答案是您需要按照您希望的方式编写处理。

我已经阅读了这个常见问题。我应该澄清一下,“强制”意味着开始明确的行为,在手机的最佳条件下提供可靠的位置。不要忙于等待直到满意或期望立即得到结果/错误代码。

从常识的角度来看,所有开发人员都希望至少有一种额外的方法来简单地请求参数中的位置,并且仅在其有效且在准确性范围内、取消或超时时才回调。如果条件阻止它,那么您无需测试深奥的行为即可使用自定义代码处理它。

为什么我需要问这个问题是:

  1. 不存在上述功能的方法

  2. 使用书中的代码(更多 Iphone 3 开发)

  3. 从头开始编写时(查看 LocateMe.xproj),发现:

  4. 模拟器行为与电话行为不同(不是谈论位置本身,这显然与 ip 查找一样好,而是 didUpdateToLocation 的行为)。认识到模拟器的局限性,该方法至少应该像在设备上那样运行。但是目前,正确编写的位置处理/检查代码只是在模拟器中超时(如在 LocateMe 示例中),而错误代码(询问一次并在回调中使用 newLocation)可以正常工作。

  5. 以及导致 [locationManager stopUpdatingLocation] 之后两次调用 didUpdateToLocation 的错误;

如果除此之外,您(像我一样)根据您的位置加载数据,并且应用程序中的多个视图都需要数据,那么 Apple 的位置获取方法的行为并不容易处理更新链 - load-calculate-present 在整个应用程序中始终如一且没有问题。特别是如果您在用户/老板的看法或决定它应该如何工作(一块石头)和系统如何工作(一个困难的地方)之间陷入困境。

这是我当前在设备和模拟器上运行的代码:

//ask for a position, as fresh as possible.
-(void)updateMeMap {
    lastloc.coordinate=homeloc.coordinate;
    lm.delegate=self;
    ctr=0;
    [self performSelector:@selector(stopUpd) withObject:nil afterDelay:gpstimeout];
    [lm startUpdatingLocation];
}

//called on each position update.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    ctr++;
    if (ctr<15) {
        NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
        NSLog(@"%d",ctr);
        if (locationAge<60) {
            NSLog(@"Found");
            ctr=40;
            homeloc.coordinate=newLocation.coordinate;
            [self stopUpd];
            [self reload];
        } else {
            NSLog(@"Lastupd");
            lastloc.coordinate=newLocation.coordinate;
        }
    } else {
            //enough tries, if not canceled choose lastloc.
        if (ctr<40) {
            NSLog(@"Last");
            ctr=40;
            homeloc.coordinate=lastloc.coordinate;  
            [self stopUpd];
            [self reload];
        }
    }
}

//force stop updates. ctr prevents extra calls after stopUpdatingLocation.
//called after the timeout delay, if position found, cancel the timeout.
-(void)stopUpd {
    [lm stopUpdatingLocation];
    lm.delegate=nil;
    if (ctr<15) {
        ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
        NSLog(@"Timeout");
        homeloc.coordinate=lastloc.coordinate;  //@need "copy"?
        [self reload];
    } else {
        ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stopUpd) object:nil];
    }
}

    // "couldn't get userlocation" handler. I also cancel like this on connectionDidFailWithError.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"Location failed: %@",[error localizedDescription]);
    ctr=0;
    [self stopUpd];
}

其中 ctr 是为了防止 2 次额外调用,lastloc 是最后已知的可靠位置,homeloc 是用于(线程)加载具有 [self reload] 的位置特定数据的电话位置。

常数 15 和 60 是来自实际测试的安全值;gpstimeout 设置为 30。如果您在模拟器中工作很多,您可能希望将其设置为 3 秒之类的短时间,因为您将得到的只是一个陈旧但相对可用的位置,并且在超时之前不会更多。

编辑:如果您能最好地使用我的代码或指出一个遗漏,我会将其标记为答案,我讨厌将我自己的代码标记为答案。

于 2011-08-18T11:25:33.277 回答
1

如果您在年龄检查中添加更多代码会怎样,例如:

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
    if (locationAge<60) {
        [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
     ...handle position
    }
}
于 2011-08-16T13:43:55.677 回答
1

我在以前的一个应用程序中遇到过类似的问题。

就我而言,没有办法强制更新位置-(我搜索了很长时间,没有找到任何东西)

我发现的一件事是使用UIBackgroundModesinfo.plist 中的密钥。

对某些类型的后台执行的支持必须由使用它们的应用程序提前声明。应用程序通过在其 Info.plist 文件中包含 UIBackgroundModes 键来声明此支持。它的值是一个数组,其中包含一个或多个具有以下值的字符串:

  • 声音的。应用程序在后台向用户播放可听内容。(这包括使用 AirPlay 流式传输音频或视频内容。)
  • location. 该应用程序让用户随时了解他们的位置,即使在后台运行时也是如此。
  • 网络电话。该应用程序使用户能够使用 Internet 连接拨打电话。

这就是你要找的。有关更多信息,请参阅文档

于 2011-08-16T12:59:52.803 回答