【问题标题】:Invoke get current coordinates every few seconds without NSTimer在没有 NSTimer 的情况下每隔几秒调用一次获取当前坐标
【发布时间】:2012-10-11 13:44:40
【问题描述】:

我知道如何使用 NSTimer 进行此操作,但我不想每隔几秒就获取当前 iPhone 坐标而无需计时器。我无法使用计时器,因为我在应用程序处于后台时获取坐标。
我已经尝试过一些东西,但这会每秒调用一次,而不是每 10 秒调用一次。
我在这里做错了什么?

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *loc = [locations objectAtIndex:0];

    NSDate* eventDate = loc.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (howRecent < 10)
    {
        CLLocation* location = [locations lastObject];

        double lat = location.coordinate.latitude;
        double lng = location.coordinate.longitude;
        NSLog(@"lat:%f lng:%f", lat, lng);

首先尝试每 10 秒执行一次后台任务,但如果我在这里执行任何操作,不知道在哪里设置时间:

- (void)applicationDidEnterBackground:(UIApplication *)application
{

    backgroundTask = [application beginBackgroundTaskWithExpirationHandler: ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (backgroundTask != UIBackgroundTaskInvalid)
            {
                [application endBackgroundTask:backgroundTask];
                backgroundTask = UIBackgroundTaskInvalid;
            }
        });
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        _pendingLocationsTimer = [NSTimer timerWithTimeInterval:_pendingLocationsTimerDuration
                                                         target:self
                                                       selector:@selector(_acceptBestAvailableLocation:)
                                                       userInfo:nil repeats:NO];


        NSRunLoop *loop = [NSRunLoop currentRunLoop];
        [loop addTimer:_pendingLocationsTimer forMode:NSRunLoopCommonModes];
        [loop run];

        dispatch_async(dispatch_get_main_queue(), ^{
            if (backgroundTask != UIBackgroundTaskInvalid)
            {
                // if you don't call endBackgroundTask, the OS will exit your app.
                [application endBackgroundTask:backgroundTask];
                backgroundTask = UIBackgroundTaskInvalid;
            }
        });
    });

}

【问题讨论】:

  • 仅依赖计时器的问题在于,您在浪费资源而无法控制或配置。在我看来,最好设置您的位置管理器,并配置一个控制器类来广播和响应适用的通知。在回答中查看我的编辑和建议。
  • 你不是在每次收到回调时都分配 eventDatehowRecent...这肯定会导致它们在每个 didUpdateLocations 回调跨度>

标签: iphone objective-c ios ios6 core-location


【解决方案1】:

我在后台状态下遇到了计时器问题。无法保证您将有一个活动的运行循环,因此在您回到前台之前,计时器永远不会触发。我所做的是:

 NSRunLoop *loop = [NSRunLoop currentRunLoop];
 [loop addTimer:myTimer forMode:NSRunLoopCommonModes];
 [loop run];

我在 BackgroundIdentifierTask 开始和结束调用中的后台线程上执行此操作。我并不完全确信我的回答是正确的,事实上我查看了您的问题,看看答案是否可以帮助我确认或纠正我对要求的理解。

如果您想持续监控位置,您还必须在默认 info.pList 中启用位置服务的后台模式。如果您只是使用重要的LocationUpdates 或地理围栏,则不需要。

我的计时器确实可以按这种方式设置并按预期触发。在此之前它不能可靠地工作。

除此之外,最好不要使用计时器。使用上面的代码,只需更改位置管理器的属性。所需的准确度和距离过滤器是可以减少经理发送新位置通知的频率的属性。

查看我刚刚在 github 上发布的我自己的位置处理程序示例,供感兴趣的人参考:

http://github.com/dsdavids/TTLocationHandler

我不认为计时器是关键。如果您在项目中删除了 TTLocationHandler 类,请查看 LMViewController 类如何响应处理程序。

NSNotificationCenter *defaultNotificatoinCenter = [NSNotificationCenter defaultCenter];
[defaultNotificatoinCenter addObserver:self selector:@selector(handleLocationUpdate) name:LocationHandlerDidUpdateLocation object:nil];

将控制器设置为观察者。每当处理程序确定已接收到新的或更准确的位置时,都会调用 handleLocationUpdate。

locationManager 在调用 startUpdating 时会发送新的位置,起初每秒发送多个位置,直到设备静止并达到准确度为止。 TTLLocationHandler 正在过滤这些事件,并且仅根据配置根据需要发送通知。

请注意,在 -(id)init 中,_recencyThreshold 设置为 60。所以我们每 60 秒保存或显示一个图钉。如果您想要更小的间隔,请更改此设置。

事实上,除非设备已接通电源,否则 TTLocationHandler 将始终在后台切换到显着的位置变化。如果使用电池供电,您将不会获得那么小的更新间隔,但您会获得更新。

我添加了一个属性来配置连续后台更新而不收费。

TTLocationHandler 使用示例

我在存储库中添加了另一个类,以展示我将如何使用 my 处理程序实现您的目标。我添加了 LMPinTracker 类,您可以在其中添加用于存储和上传位置的代码。

查看 LMAppDelegate.m

    self.pinTracker.uploadInterval = 30.00;

将其更改为您想要的上传到服务器之间的任何间隔。

    self.sharedLocationHandler.recencyThreshold = 5.0;

将 5.0 更改为您希望存储位置之间的最短时间。这不会是准确的,会因行进速度和信号强度而异,但基本上,在 x 秒间隔后,它会认为存储的位置已过时并尝试获取另一个准确的位置。

现在查看 LMPinTracker.m 文件
将您的数据存储代码放在这两行之后:

    // Store the location into your sqlite database here
    NSLog(@"Received location info: %@ \n Ready for store to database",lastKnowLocationInfo);

在此评论之后将您的网络上传代码放在此处:

    // Do your upload to web operations here

评论

这应该做你想做的事,同时仍然尊重用户电池和后台操作。

基本上,当用户在旅行时,更新将按照您设置的时间间隔连续进行。
当用户静止不动时,不会有更新,也不会有重要的活动。
当没有新活动时,您也不会上传到网络。
当用户再次开始移动时,会继续记录和更新。

如果我是你,想要进一步完善它,我会考虑设置一个区域和时间来检查。如果用户长时间保持静止,则仅切换到显着位置更新。然后,您将关闭定位服务,但在用户再次启动时重新启动。

【讨论】:

  • 你能提供更多的代码吗?当应用程序处于后台时,如何在任何时间间隔内执行任何任务,这将成为噩梦。不仅位置我无法在后台运行任何任务...
  • @1110 查看链接。您应该在该存储库中看到您需要的所有内容。随意使用。
  • 我试图从你的代码中只得到我需要的东西。而且我只是不想实现部分(开始时)在后台每 10 秒做一次我会用部分新代码更新我的问题,我不明白一些...
  • 我认为您可能在计时器上走错了路。请参阅我对答案的编辑。
  • 当您收到该位置时,请告诉我您打算如何处理它。我将向您展示如何根据您的目的修改 LMViewController 中的方法。
【解决方案2】:

我认为您可以使用计时器在后台执行此操作:

[NSTimer scheduledTimerWithTimeInterval:kAlertInterval target:self selector:@selector(checkLoc:) userInfo:nil repeats:YES];

在你的方法中:

- (void)checkLoc:(NSTimer *)timer {
    //...get your location and...
     if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
        //Do your background stuff
    }
}

我在某些应用程序中使用了此代码。请告诉我它是否适合您。

【讨论】:

  • No NSTimer 在 app go 的后台模式下肯定不起作用。我刚试过。
  • 你在 plist 属性中设置了 backgroundMode 吗?使用值位置设置 UIBackgroundModes。我还建议您阅读此link
猜你喜欢
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 2015-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多