Вызывать текущие координаты каждые несколько секунд без NSTimer
Я знаю, как сделать это с 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;
}
});
});
}
2 ответа
У меня были проблемы с таймерами в фоновом состоянии. Нет гарантии, что у вас будет активный цикл выполнения, и поэтому таймер никогда не сработает, пока вы не вернетесь на передний план. Что я сделал, это:
NSRunLoop *loop = [NSRunLoop currentRunLoop];
[loop addTimer:myTimer forMode:NSRunLoopCommonModes];
[loop run];
Я делаю это в фоновом потоке внутри BackgroundIdentifierTask начала и завершения вызовов. Я не совсем уверен, что у меня все правильно, на самом деле я посмотрел на ваш вопрос, чтобы увидеть, может ли ответ помочь мне подтвердить или исправить мое понимание требований.
Вы также должны включить фоновый режим для служб определения местоположения, включенный в ваш info.pList по умолчанию, если вы хотите постоянно отслеживать местоположение. Вам это не нужно, если вы просто используете значимые атрибуты местоположения или геозону.
Мой таймер работает и работает так, как задумано. До этого он не работал надежно.
Кроме того, вы можете быть лучше без таймера. Используя ваш код выше, просто измените свойства вашего менеджера местоположения. Требуемая точность и дистанционный фильтр - это свойства, которые снижают частоту отправки менеджером уведомления о новом местоположении.
Посмотрите пример моего собственного обработчика местоположения, который я только что опубликовал на github для всех, кто заинтересован:
http://github.com/dsdavids/TTLocationHandler
Я не думаю, что таймер является ключом. Если вы удалите класс TTLocationHandler в своем проекте, посмотрите, как класс LMViewController реагирует на обработчик.
NSNotificationCenter *defaultNotificatoinCenter = [NSNotificationCenter defaultCenter];
[defaultNotificatoinCenter addObserver:self selector:@selector(handleLocationUpdate) name:LocationHandlerDidUpdateLocation object:nil];
устанавливает контроллер в качестве наблюдателя. Всякий раз, когда обработчик определяет, что получено новое или более точное местоположение, вызывается handleLocationUpdate.
LocationManager, когда вызывается startUpdating, будет отправлять новые местоположения, много раз в секунду вначале и при перемещении, пока устройство не станет неподвижным и не будет достигнута точность. TTLocationHandler фильтрует эти события и отправляет уведомление только по мере необходимости на основе конфигурации.
Обратите внимание, что в -(id)init, _recencyThreshold установлен на 60. Поэтому мы сохраняем или отображаем пин-код каждые 60 секунд. Если вы хотите меньший интервал, измените это.
Таким образом, TTLocationHandler всегда будет переключаться на значительные изменения местоположения в фоновом режиме, если устройство не подключено к источнику питания. Вы не получите такой маленький интервал между обновлениями, если он работает от батареи, но вы получите обновления.
Я добавил свойство для настройки для непрерывных фоновых обновлений без зарядки.
Пример использования TTLocationHandler
Я добавил еще один класс в хранилище, чтобы показать, как я смогу достичь ваших целей с помощью моего обработчика. Я добавил класс 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
Комментарии
Это должно делать то, что вы хотите сделать, при этом соблюдая при этом батарею пользователя и фоновую работу.
В основном, когда пользователь путешествует, обновления будут выполняться непрерывно с установленным вами интервалом.
Когда пользователь стоит на месте, не будет никаких обновлений и значительных действий.
Если нет новых действий, вы также не будете загружать их в Интернет.
Регистрация и обновление возобновляются, когда пользователь снова начинает движение.
Если бы я был вами, желая уточнить его, я бы подумал об установке региона и времени для проверки. Если пользователь остается неподвижным в течение некоторого времени, переключитесь только на значительное время обновления. Затем вы выключите службы определения местоположения, но будете снова включены, когда пользователь снова начнет работу.
Я думаю, что вы можете сделать это в фоновом режиме с таймером:
[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
}
}
У меня этот код работает в некоторых приложениях. Пожалуйста, скажите мне, если это работает для вас.