2

我知道如何用 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;
            }
        });
    });

}
4

2 回答 2

2

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

 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。

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

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

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

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

TTLLocationHandler 的使用示例

我在存储库中添加了另一个类,以展示我将如何使用 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

评论

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

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

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

于 2012-10-11T14:54:04.703 回答
0

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

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

我有这个代码在一些应用程序中工作。请告诉我它是否适合你。

于 2012-10-11T14:11:27.160 回答