强制位置更新

发布于 2024-11-29 13:33:22 字数 1082 浏览 4 评论 0原文

我试图克服 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,如果这会影响它的话。

我愿意接受替代代码解决方案,以确保您拥有新的职位。

I'm attempting to overcome a sometimes-failure of didUpdateToLocation when checking local data based on current position, closing the app, traveling a bit, and opening the app again. What happens is that the user visits one place, checks the list, goes to another place, and the list is updated but using the old location data.

I would like to make sure I have a fresh newLocation.

What's wrong with this code?

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
}

The symptoms are that cc is about 1200 seconds on app start, then on each retry it increases a few seconds.

I've tried -[newLocation.timestamp timeIntervalSinceNow], and similarly it increases a few seconds at each retry. At one point the interval was ~2400.

I'm using FilterNone and AccuracyBest, if that could influence it.

I'm open to alternative code solutions to make sure you have a fresh position.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝咒 2024-12-06 13:33:22

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

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

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

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

  1. 不存在如上所述的方法

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

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

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

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

如果除此之外,您(像我一样)根据您的位置加载数据,并且应用程序中的多个视图需要这些数据,则 Apple 的位置获取方法的行为并不容易处理更新链 -整个应用程序中的加载-计算-呈现一致且没有问题。特别是当你陷入用户/老板的看法或决定如何工作(困难)和系统如何工作(困难)之间时。

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

//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 是用于(线程)加载的电话位置具有[自动重新加载]的特定于位置的数据。

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

编辑:如果您可以最好我的代码或指出遗漏,我会将其标记为答案,我讨厌将自己的代码标记为答案。

The answer was that you need to write the handling the way you want it to behave.

I've read up on this common problem. I should have clarified that "force" means to start unambiguous behavior that gives a reliable position under optimal conditions for the phone. Not to busy-wait until satisfied or to expect an immediate result/error code.

From a common sense viewpoint, what would be desirable by all developers would be at least an extra method to simply ask for a position within parameters, and callback only when it's valid and within accuracy, or canceled, or timed out. If the conditions prevent it you then don't need to test out esoteric behavior to be able to handle it with custom code.

Why I needed to ask about this at all was:

  1. no existence of a method functioning as described above

  2. using code from a book (More Iphone 3 Development)

  3. when writing it from scratch (looking at LocateMe.xproj), discovering that:

  4. simulator behavior differs from phone behavior (not talking about the position itself, which is obviously as good as ip lookup can make it, but the behavior of didUpdateToLocation). Recognizing the limitations of a simulator, the method should at least behave like they do on a device. But currently, correctly written location handling/checking code just times out in the simulator (as in the LocateMe example), while incorrect code (asking once and using newLocation on callback) works.

  5. and a bug causing didUpdateToLocation being called twice after [locationManager stopUpdatingLocation];

If on top of this you (like I) load data based on your position, and the data is required by multiple views in your application, the behavior of Apple's location-fetching methods doesn't make it easy to handle the chain of update-load-calculate-present consistently and problem-free throughout the app. Especially if your stuck between user/boss perception or decision of how it should work (a rock) and how the system works (a hard place).

Here's my current code which works on a device and in a simulator:

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

Where ctr is there to prevent the 2 extra calls, lastloc is last known reliable position, homeloc is the phone position used for (threaded) loading of location-specific data with [self reload].

The constants 15 and 60 are safe values from real-world testing; gpstimeout is set to 30. If you work a lot in a simulator you may want to set it to something short like 3 seconds, as all you will get is a stale but relatively usable position and no more until the timeout.

Edit: If you can best my code or point out an omission, I'll mark that as answer, I hate marking my own as answer.

揪着可爱 2024-12-06 13:33:22

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

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

我发现的一件事是在我的信息中使用 UIBackgroundModes 键.plist。

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

  • audio。该应用程序在用户处于
    背景。 (这包括使用流式传输音频或视频内容
    AirPlay。)
  • 位置。该应用程序让用户了解他们的情况
    位置,即使在后台运行时也是如此。
  • voip。应用
    为用户提供使用电话拨打电话的能力
    互联网连接。

这就是您正在寻找的。有关详细信息,请参阅文档

I've come across a similar problem in one of my previous apps.

There's no way to force a location update as far as I'm concerned - (I searched for a long time and didn't find anything)

One thing that I found was using the UIBackgroundModes key in my info.plist.

Support for some types of background execution must be declared in advance by the application that uses them. An application declares this support by including the UIBackgroundModes key in its Info.plist file. Its value is an array that contains one or more strings with the following values:

  • audio. The application plays audible content to the user while in the
    background. (This includes streaming audio or video content using
    AirPlay.)
  • location. The application keeps users informed of their
    location, even while running in the background.
  • voip. The application
    provides the ability for the user to make phone calls using an
    Internet connection.

Which is what you're looking for. See the docs for more info.

白昼 2024-12-06 13:33:22

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

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

What if you put more of the code within the age check, like:

-(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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文