我写了一个应用程序监视用户的位置。当我的视图加载时,位置服务会打开:
// 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分钟后进入后台模式,它附加到调试器上,方法将终止调用:
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分钟。
答案 0 :(得分:2)
来自Apple的文档:
应用终止
应用程序必须准备好终止,以便随时发生 不要等待保存用户数据或执行其他关键任务。 系统启动的终止是应用程序生命周期的正常部分。 系统通常终止应用程序,以便它可以回收内存和 为用户启动的其他应用程序腾出空间,但系统 也可以终止行为不端或不响应的应用 事件及时发生。
暂停的应用在终止时不会收到通知;该 系统终止进程并回收相应的内存。如果 应用程序当前正在后台运行而不是暂停, 系统调用其应用委托的applicationWillTerminate:之前 终止。设备时系统不会调用此方法 重新启动。强>
除了系统终止您的应用外,用户还可以终止 您的应用程序显式使用多任务UI。用户启动 终止与终止暂停的应用程序具有相同的效果。该 应用程序的进程被终止,并且没有向该应用程序发送通知。
关于significantChangesLocation:
如果您让重要更改位置服务正在运行并且您正在运行 iOS应用程序随后被暂停或终止,该服务 新位置数据到达时自动唤醒您的应用。
如果您不想通过significantChangeLocation唤醒您的应用,则可以在backgroundTimeRemaining即将到期时调用stopMonitoringSignificantLocationChanges。
ATT。