(iOS) Несколько уведомлений через locationManager: didExitRegion: при выходе из региона - PullRequest
6 голосов
/ 16 февраля 2012

Я работаю над приложением на основе определения местоположения, которое использует мониторинг региона CLLocationManager.

Я использую один CLLocationManager и один делегат (которые настраиваются в делегате основного приложения при запуске), и я замечаю, что часто получаю серию вызовов для моего делегата (в locationManager: didExitRegion :) при выходе из отслеживаемой области - обычно два вызова, но иногда больше.Кто-нибудь еще сталкивался с этим, или есть идеи, что может пойти не так?

Я создаю экземпляр CLLocationManager следующим образом в классе, который создается в делегате приложения:

    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    _locationManager.delegate = self;

Я настраиваю мониторинг региона следующим образом:

    // The region instance has a radius of 300 meters
    [_locationManager startMonitoringForRegion:region desiredAccuracy:1000];

Как я понимаю из документации , обеспечение требуемой точности 1000 означает, что locationManager: didExitRegion: должен вызываться только один размы находимся на расстоянии 1000 метров от региона.

По дополнительному пункту - насколько я видел, я получаю серию всплывающих уведомлений, только если я нахожусь в машине (и поэтому путешествую довольно быстро),Кажется, этого не случится, если я на велосипеде или пешком.Любые указания относительно того, что я делаю неправильно (или, если это проблема, с которой уже сталкивались другие), приветствуются.

Ответы [ 5 ]

6 голосов
/ 01 марта 2012

tl; dr: Это действительно довольно просто - вы получаете столько информации, сколько Apple может дать вам о том факте, что вы пересекаете границы вышек сотовой связи, то есть совсем не очень хорошие данные.

Теперь реальная история:

Как правило, есть только несколько способов, которыми CoreLocation может определить свою позицию:

  • По GPS.Это очень точно (десятки метров), но потребляет много энергии.
  • По WiFi.Это , как правило, точно, хотя базовые станции Wi-Fi могут изменяться, что делает их нечеткими.Этот метод выполняет перекрестные ссылки на станции Wi-Fi в этой области по сравнению с некоторыми известными точными местоположениями - поэтому он знает, когда он видит «FooWifiStation», что он связан с определенной областью, измеренной точными инструментами, или, возможно, даже другими телефонами с включенным GPS (которыйявляется спорным, мы никогда не узнаем, если Apple, использует этот метод)
  • местоположений ячейки башни.Они не двигаются, поэтому он знает, что вы находитесь в большой нечеткой точке покрытия, когда вы связаны с башней.Это наименее точное, но наименее энергозатратное решение, поскольку ваш телефон уже выполняет работу, чтобы оставаться на связи.

Вы даже можете увидеть это, если зайдете вПриложение карт «холодное»: вы сразу же начинаете с большой нечеткой синей точки (по крайней мере, в 1 км от места, где я нахожусь), затем оно сжимается при получении определения местоположения Wi-Fi, а затем более или менее исчезает, когда GPS получает свое исправление.Он выполняет [cell tower] => [wifi] => [gps] в режиме реального времени.

По моему опыту, пункт «значительное изменение местоположения» означает «Мы сообщим вам, когда вы переедете вбольшой путь, , если нам не нужно больше работать или тратить больше сил, чтобы получить эти данные . Это означает, что де-факто самое лучшее, на что вы можете положиться, - это использовать переходы междуApple намеренно оставил это расплывчатым, потому что, если другое приложение использует что-то с более высоким разрешением - скажем, вы открываете Maps.app, и оно получает исправление GPS - возможно, вы внезапно получите отлично исправить местоположение, но вы не можете полагаться на то, что это всегда так. Вы попросили "слабую ссылку" на местоположение.

Теперь подумайте о том, что происходит, когда вы бродите в своей машинеВаш сотовый телефон должен управлять этим переходом. Он передается, разговаривает с несколькими башнями одновременно, такого рода вещи, чтобы управлять плавным переходом, который должен быть жизнеспособным в то время какВы разговариваете .Просто это довольно изящный подвиг для любой маленькой коробочки.Обязательно, это приведет к появлению некоторого отскока в обновлениях местоположения, потому что в данный момент для телефона вы вибрируете между вышками сотовой связи, когда он согласовывает переход.

Так, что на самом деле означает радиусЭто то, что вы заинтересованы в данных примерно такой точности, но API не будет гарантировать, что вы получите обновления в пределах этого радиуса.Вы можете думать об этом как о том, что Apple говорит: «Мы собираемся объединить вашу точность в одну из трех групп - но мы не дали вам список, потому что мы хотим оставить за собой право разрабатывать более эффективные методы определения вашего местоположения безВы должны изменить свой код ".Конечно, в действительности любое реальное приложение изменится, если они поменяют свой метод получения местоположения, потому что они раздражающе расплывчаты в этом материале о местоположении.

Другими словами, вы получитеопределение местоположения в вышке сотовой связи с некоторыми полностью выдуманными предположениями о том, насколько хороша эта точность;когда вы переходите к следующей башне, вы мгновенно переходите к ее местоположению с таким же нечетким исправлением - имеет ли это смысл?CoreLocation сообщает вам, что вы на вышке сотовой связи с точностью до того, как далеко достигает сигнал вышки сотовой связи;когда вы перейдете к другой башне, вы, вероятно, получите бодрость передачи.

Так что, когда дело доходит до того, чтобы действительно хорошо выполнить свою работу, вы должны предположить, что данные относятся к категории "отлично", "хорошо" или "плохо", и использовать другие методы, например фильтры Калмана - если вам действительно нужно лучше угадать, где находится пользователь.В качестве приближения нулевого порядка я бы просто отменил обратные вызовы на основе time обновления, которое дано, и предположил, что пользователь на самом деле не прыгает километры назад и вперед в течение нескольких секунд,скорее, путешествуя в направлении первого нового обновления.

5 голосов
/ 28 февраля 2012

Я думаю, что вам будет лучше, если использовать желаемую точность, которая на меньше , чем радиус 300 м, т.е. kCLLocationAccuracyHundredMeters.Вы пробовали это?Нет документации о лежащей в основе логике, но я бы предположил, что desiredAccuracy можно рассматривать как минимальное расстояние, которое вам нужно пройти, что движение считается "пересечением границы".
Мониторинг региона основан на «значительных событиях местоположения», а не на GPS - иначе батарея не будет работать полдня.

Если вы используете такой высокий desiredAccuracy, система может получить более одногозначительное событие местоположения (кажется, что оно генерируется примерно через каждые 500 м - также в зависимости от того, сколько беспроводных сетей у вас есть в этом районе. В этом случае система может сравнить текущее местоположение в результате значительного изменения с расстоянием до всех сторон вашего регионаЕсли вы находитесь за пределами 1000 м от противоположной стороны вашего региона, он может уведомить снова и прекратить уведомлять только один раз, когда вы находитесь за 1000 м от каждой стороны вашего региона.

Причинапараметр точности - скорее избегать пересечения границ, если вы слишком близко к границе, так чтоВы не видите внутреннюю-внешнюю-внутреннюю-внешнюю сторону и т.д., когда путешествуете только за пределами границы ...

В своих приложениях я пробовал много разных комбинаций радиуса и точности и остановился на 500, 100 и 100 м/ 10 м - это очень хорошо работает в моей реальной работе внутри города.

(см. Также прекрасную серию статей http://longweekendmobile.com/2010/07/22/iphone-background-gps-accurate-to-500-meters-not-enough-for-foot-traffic/)

2 голосов
/ 24 февраля 2012

Держу пари, что это ваша проблема, locationManager:didExitRegion: вызывается для КАЖДОГО региона, который зарегистрировал каждый менеджер местоположения в каждом приложении на вашем iPhone.Вам необходимо сравнить строку идентификатора региона, отправленную в качестве параметра, со строкой идентификатора региона, с которым ваше приложение должно что-то делать в данный момент.

Когда вы отправляете [_locationManager startMonitoringForRegion:region desiredAccuracy:1000];, вы создаете регион, еслион еще не существует для мониторинга.Это НЕ то же самое, что добавить наблюдателя в NSNotification Center.Объект региона Apple слепо отправляет уведомление КАЖДОМУ CLLocationManager, который затем отправляет сообщение делегату.

0 голосов
/ 30 июля 2013

Я обнаружил, что для экономии батареи необходимо использовать monitorForSignificantLocationChange.Мое решение состоит в том, чтобы отфильтровать несколько оповещений, приходящих в течение 60 секунд для одного и того же региона:

-(BOOL)checkForMultipleNotifications:(GeoFenceModel*)fence
{
  GeoFenceModel *tempFence = [fenceAlertsTimeStamps objectForKey:fence.geoFenceId];
  if(tempFence == nil){
    fence.lastAlertDate = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]];
    [fenceAlertsTimeStamps setObject:fence forKey:fence.geoFenceId];
    NSLog(@"checkForMultipleNotifications : no Notifications found for Region : %@, Adding to Dictionary with timestamp %.1f",fence.geoFenceId,fence.lastAlertDate.doubleValue);
  }
  else if(([[NSDate date] timeIntervalSince1970] - fence.lastAlertDate.doubleValue) <= 60.0){
    NSLog(@"checkForMultipleNotifications : Multiple region break notifications within 60 seconds, skipping this alert");
    return NO;
  }
  return YES;
}
0 голосов
/ 26 февраля 2012

Во-первых, документация не указывает на то, что только требуемая точность определяет, как далеко от региона вам нужно находиться до того, как будет сгенерировано событие didExitRegion.Если вы хотите точно настроить частоту возникновения событий, вам также необходимо использовать distanceFilter, который определяет горизонтальное перемещение, которое необходимо переместить до того, как событие будет запущено.

Если используется distanceFilterне работает, тогда я бы порекомендовал следующее:

  1. Если вы используете NSNotificationCenter, убедитесь, что вы удалили другие классы из уведомлений через [[NSNotificationCenter defaultCenter] removeObserver: self],При желании вы можете указать имя и объект для этого вызова.

  2. 1000 км - это большой радиус, который с высокой вероятностью может пересекаться со многими регионами поблизости.Я бы попробовал меньшее значение для этого параметра, чтобы увидеть, не уменьшает ли это количество уведомлений о выходе, которые вы получаете.Единственное, что указывает на то, что это не может быть решением, это то, что вы не сказали, что также получаете взрывы didEnterRegion.

  3. Наконец, я бы проверил идентификатор объекта CLRegion.передается в didExitRegionEvent, чтобы увидеть, если вы не можете самостоятельно установить NSDictionary регионов.Вам нужно установить регион в словарь на didEnterRegion и удалить его на didExitRegion.Итак, на didExitRegion все, что вам нужно сделать, это убедиться, что вы заинтересованы в регионе, проверив, что у вас уже есть регион.Я полагаю, что CLRegion уже оснащен isEqual: и хешем, позволяющим хранить его в коллекции.

Удачи!

...