iOS Не типичная проблема таймера фонового отслеживания местоположения
Я разрабатываю пример приложения, которое отслеживает положение пользователя в фоновом режиме, но я не хочу оставлять службу определения местоположения всегда включенной, но что-то в моем таймере не работает должным образом.
Моя идея состояла в том, что каждые x минут служба запускается, и когда она имеет правильное новое местоположение, она снова освобождается, теперь для тестирования устанавливается значение 10 секунд. (Значительное LocationChange не сработало, недостаточно обвинено)
Я много искал (iOS Dev center + Stackru) и нашел "новые" функции определения местоположения фона, которые позволяют запускать код в течение 10 минут после перехода к фону, используя beginBackgroundTaskWithExpirationHandler, несколько блоков и таймер.
Я установил фоновый режим на Location, и теперь я думаю, что мне не нужно обрабатывать конец фонового времени (сначала я хочу получать местоположение каждые 15-20 секунд)
код работает "отлично", но:
- Таймер иногда срабатывает, иногда нет.
- Когда таймер срабатывает, это займет минимум 10 минут.
- Некоторые случайные действия в ОС (например, вход на рабочий стол поиска), по-видимому, стимулируют срабатывание таймера (не уверен в этом, я не понимаю, как это возможно, но это так...)
И через код будет еще один вопрос.
методы appdelegates:
//applicationDidEnterBackground
- (void)applicationDidEnterBackground:(UIApplication *)application{
NSLog(@"to background");
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
_triggertimer = nil;
[self initTimer];
});
NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);}
//initTimer
- (void) initTimer{
NSLog(@"InitTimer ");
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
_triggertimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:@selector(checkUpdates:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_triggertimer forMode:NSDefaultRunLoopMode] ;
[[NSRunLoop currentRunLoop] run];
}];}
//checkUpdates
- (void)checkUpdates:(NSTimer *)timer{
NSLog(@"CheckUpdates ");
UIApplication* app = [UIApplication sharedApplication];
if (nil == _locationManager) _locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.distanceFilter = 10;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[_locationManager startUpdatingLocation];
[_locationManager startMonitoringSignificantLocationChanges];
double remaining = app.backgroundTimeRemaining;
NSLog(@"Reminaing %f", remaining);}
Я пытался многое исправить, и, может быть, я что-то напутал или пропустил... Что ты видишь? возможно некоторые концептуальные ошибки, я пытаюсь представить себя блокам, и я еще не делаю их ¬¬
Кстати, почему все коды, которые я нашел, содержат это, прежде чем делать что-либо с beginBackgroundTaskWithExpirationHandler?
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
Я думал, что это для того, чтобы взять те 600 секунд фона... но я не уверен!
2 ответа
Хорошо, проблема была в том, что я дважды вызывал beginBackgroundTaskWithExpirationHandler, один в ApplicationDidEnterBackground, а другой внутри initTimer...
Когда ваше приложение заземлено, таймер больше не будет срабатывать, если у вас не установлено значение "location" для ключа UIBackgroundModes в info.plist приложения.
Вы можете продлить время, в течение которого вам разрешено работать в фоновом режиме (если вы не установили "location"), используя beginBackgroundTaskWithExpirationHandler, но это всегда должно быть связано с соответствующим завершающим вызовом.