IOS Не типичная проблема таймера отслеживания местоположения фона

Я разрабатываю пример приложения, которое отслеживает позицию пользователя в фоновом режиме, но я не хочу, чтобы служба определения местоположения всегда включалась, но что-то в моем таймере не ведет себя правильно.

Моя идея заключалась в том, что каждые x минут, обслуживание продолжается, и когда у него есть правильное новое место, оно снова выдается, теперь для тестирования установлено 10 секунд. (Значительное LocationChange не трюк, недостаточно точный)

Я много искал (iOS Dev center + StackOverflow) и обнаружил "новые" функции фонового местоположения, которые позволяют запускать код через 10 минут после перехода на задний план, используя startBackgroundTaskWithExpirationHandler, несколько блоков и таймер.

Я установил фоновый режим в "Местоположение", и теперь я думаю, что мне не нужно обрабатывать конец фонового времени (сначала я хочу получить место каждые 15-20 секунд).

код работает "отлично", но:

  • Иногда срабатывает таймер, иногда нет.
  • Когда срабатывает таймер, для этого требуется не менее 10 минут.
  • Некоторые случайные действия в ОС (например, ввод на рабочий стол для поиска), по-видимому, оценивают таймер для запуска (не уверенный в этом, я не понимаю, как это возможно, но там он...)

И по коду будет другой qüestion.

методы 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 секунд фона... но я не уверен!

Ответ 1

Хорошо, проблема заключалась в том, что я дважды вызывал beginBackgroundTaskWithExpirationHandler, один в ApplicationDidEnterBackground, а другой внутри initTimer...

Ответ 2

Когда ваше приложение подсвечено, таймер больше не будет гореть, если у вас нет значения "location" для ключа UIBackgroundModes, указанного в информации о приложении .plist.

Вы можете продлить время, которое вам разрешено выполнять в фоновом режиме (если вы не установили "местоположение" ), используя startBackgroundTaskWithExpirationHandler, но это всегда должно быть сопряжено с соответствующим конечным вызовом.