【发布时间】:2015-03-11 00:08:50
【问题描述】:
我编写了一个应用程序来监控用户的位置。当我的视图像这样加载时,定位服务已打开:
// Create the location manager if this object does not
// already have one.
if (nil == self.locationManager) {
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startMonitoringSignificantLocationChanges];
NSLog(@"Started monitoring significant location changes");
如果我在应用程序处于活动状态时终止该应用程序,定位服务将停止。这是我为停止 AppDelegate.m 中的位置服务而编写的代码:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also
applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
NSLog(@"entered terminate in delegate");
[myController.locationManager stopUpdatingLocation];
[myController.locationManager stopMonitoringSignificantLocationChanges];
myController.locationManager = nil;
[self saveContext];
}
我遇到了一个问题,如果我的应用程序已经在后台,则不会调用上述方法,因此我无法关闭定位服务。为了解决这个问题,我找到了我尝试过的这个解决方案:
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)]) {
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Synchronize the cleanup call on the main thread in case
// the task actually finishes at around the same time.
dispatch_async(dispatch_get_main_queue(), ^{
if (self.bgTask != UIBackgroundTaskInvalid)
{
NSLog(@"Marking bgTask as Invalid when we entered background");
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}
});
}];
}
}
因此,如果我的应用程序在后台,则上述解决方案有效。但是,我注意到如果让我的应用程序在后台运行很长时间,超过五分钟,过期处理程序就会启动。那么,如果我终止应用程序而不将其带到前台。定位服务图标仍然出现在手机上。我必须先重新启动应用程序或将其置于前台,然后再将其终止以启用禁用定位服务的代码。
如果我删除这两行:
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
然后在连接调试器的五分钟后停止位置服务工作。如果我让它在后台运行更长时间,那么终止代码永远不会启动。是因为我没有改变位置还是应用程序最终死掉了?
所以我的问题是,如果应用程序在后台运行了一段时间,是否有另一种方法可以确保应用程序正确停止位置服务监控?
谢谢你...Amro
编辑,我做了更多实验,以下是我的发现:
如果我在调试器进入后台模式后等待 11 分钟,则连接到调试器时,将调用方法 willTerminate:
2015-01-13 08:52:45.935 [441:37074] @@@AMRO--->applicationWillResignActive entered
2015-01-13 08:52:46.642 [441:37074] @@@AMRO--->Entered background mode
2015-01-13 08:55:42.697 [441:37074] @@@AMRO--->beginBackgroundTaskWithExpirationHandler called
2015-01-13 09:03:26.265 [441:37074] entered terminate in delegate
如果我在没有调试器的情况下尝试此操作,并且只等待四分钟,则不会调用终止函数,我不必等待整个 11 分钟。
【问题讨论】:
-
看看这个帖子stackoverflow.com/questions/24778492/…,听起来也有类似的问题,你有没有在后台模式下开启位置更新?
-
@GuyS 是的,我需要在后台模式下进行位置跟踪。根据我的问题和实现细节,如果后台应用程序在后台运行超过 5 分钟,您提供的堆栈溢出链接中的解决方案将不起作用
-
您确定是 5 分钟而不是 3 分钟吗?在 iOS 7 中,后台任务在 3 分钟后停止,我不确定它是否在 ios 8 中更改(我不这么认为)。无论如何,我使用这篇文章stackoverflow.com/questions/18901583/… 在后台获取位置更新,我刚刚检查过,它现在在后台获取位置更新 20 分钟......只需确保添加 requestAlwaysAuthorization 和 plist 字符串 NSLocationAlwaysUsageDescription。希望这会有所帮助
-
你说得对,我计时了:2015-01-13 08:46:38.468 @@@AMRO--->进入后台模式 2015-01-13 08:49:34.472 @@@ AMRO---> beginBackgroundTaskWithExpirationHandler 被调用。对我来说,问题不在于定位服务。它终止应用程序并能够优雅地关闭位置服务。关于请求授权和编程已实现的 PLIST。所以基本上如果我离开它超过三分钟,然后尝试杀死应用程序,applicationWillTerminate 方法永远不会被调用。
标签: ios objective-c cllocationmanager