(iOS) Multiple notifications via locationManager: didExitRegion: when leaving a region

I am working on a local application that uses CLLocationManager scope monitoring.

I use one CLLocationManager and one delegate (which is installed in the main application at startup), and I notice that I often get a package of several calls for my delegate (in locationManager: didExitRegion:) when leaving the controlled region - usually two calls, but sometimes more. Has anyone else experienced this or had any ideas what could go wrong?

I create an instance of CLLocationManager as follows, in a class that is created in the application delegate:

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

I set up region monitoring as follows:

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

As I understand from the documentation , ensuring the required accuracy of 1000 means that locationManager: didExitRegion: should only be called once when we are 1000 meters outside the region.

At another point - as far as I saw, I only get multiple notifications if I'm in the car (and therefore travel pretty fast). This does not seem to happen if I'm on a bike or on foot. Any guidance regarding what I am doing wrong (or if this is a problem that others have encountered) is appreciated.

+6
source share
5 answers

tl; dr: It's really very simple - you get as much information as Apple can tell you that you cross cell boundaries, which means that the data is not very good.

Now the real story:

Typically, there are only a few ways that CoreLocation can determine one position:

  • By GPS. It is very accurate (tens of meters), but it consumes a lot of energy.
  • Via wifi. This is usually accurate, although Wi-Fi base stations can and can vary, making it fuzzy. This method cross-references Wi-Fi stations in the area compared to some known exact locations - so it knows when it sees the “FooWifiStation” that it is associated with a specific area measured by precision instruments or perhaps even with other phones turned on GPS (which is inconsistent, we may never know if Apple uses this method)
  • In the locations of the cells. They do not move, so he knows that you are at a large fuzzy point of coverage when you are connected to the tower. This is the least accurate, but the least energy intensive, because your phone is already working to stay in touch.

You can even see this if you enter the cold map app: you start right away with a big fuzzy blue dot (at least 1 km where I am), then it shrinks when it receives a Wi-Fi location correction, then it more or less disappears when the GPS receives its correction. It does the accuracy of [cell tower] => [wifi] => [gps] in real time.

In my experience, the “significant change of location” position means “We will let you know when you will move to a large extent, if we don’t need to work anymore or spend more energy to get you, this data. This means that de facto, that the best you can rely on is to use the transitions between the cell towers.Apple deliberately left it undefined because if another application uses something that has the best resolution - let's say you open Maps.app and it gets GPS fix - POSSIBILITY you suddenly get an excellent fix to a site, but you can not depend on what always happens. You asked for "weak link" in the location.

Now think about what happens when you wander in your car: your mobile phone must control this transition. It is transmitted, talking to several towers at once, something like that, to control a smooth transition, which should be viable while you are talking. It’s just a pretty neat feat for any small box. Surely this will lead to the fact that you will find a certain number of failures in location updates, because, to the phone, you vibrate between the cell towers at this time when it negotiates the transition.

So, that radius really means that you are interested in data of approximately the same accuracy, but the API does not guarantee that you will receive updates in this radius. You might think about it, because Apple says: "We collect your accuracy in one of three groups, but we did not indicate your listing, because we want to keep the right to develop better methods for fixing your location without you need to change your code." Of course, in fact, any real application will change if they change their way of obtaining location, because they are annoyingly vague in this place.

In other words, you will get a location correction on the mesh tower with some hunch about how good this accuracy is; when you go to the next tower, you instantly go to its location, with a similar fuzzy correction - does this make sense? CoreLocation tells you that you are on a mesh tower with precision until the cell signal reaches; as you move to another tower, you are likely to get a pep transfer.

So, when it comes to this, to really do a good job, you must assume that the data is “great”, “good” or “bad” and use other methods - for example, Kalmann Filters - if you really need to better guess where the user is located. As a zeroth order approximation, I would simply cancel the callbacks based on the update time given, and suppose the user does not jump in different directions for several seconds, but rather travels in the direction of the first new update.

+6
source

I think you will be better off using the desired accuracy, which is less than a radius of 300 m, i.e. kCLLocationAccuracyHundredMeters . Have you tried this? There is no documentation about the basic logic, but I would suggest that the desiredAccuracy can be regarded as the minimium distance that you will need to travel, that the movement is considered a "border crossing".
Monitoring the region is based on “significant location events,” not GPS — otherwise the battery will not work for half a day.

If you use such a high desiredAccuracy , the system can receive more than one significant location event (they seem to be generated approximately every 500 m - it also depends on how many Wi-Fi networks you have in this area. In this case, the system can compare the current location in the result of significant changes with the distance to all sides of your region.If you are outside 1000 m from the opposite side of your region, it can notify you again and only stop notifying you beyond 1000 m from each side of your region.

The reason for the accuracy parameter is rather to avoid border crossings if you are too close to the border, so you cannot see inside-outside-inside-outside, etc. while traveling abroad ...

In my applications, I tried many different combinations of radius and accuracy and relied on 500 m / 100 m and 100 m / 10 m - they work very well in my real work inside the city.

(see also an excellent series of articles http://longweekendmobile.com/2010/07/22/iphone-background-gps-accurate-to-500-meters-not-enough-for-foot-traffic/ )

+5
source

I bet this is your problem, locationManager:didExitRegion: called for EVERY region that each location manager has registered in every application on your iPhone. You need to compare the region identifier string sent as a parameter with the region identifier string of the region in which you want your application to do something currently.

When you send [_locationManager startMonitoringForRegion:region desiredAccuracy:1000]; , you create a region if it does not already exist for control. This is NOT the same as adding an observer to the NSNotification Center. The Apple scope object blindly sends a notification to EVERY CLLocationManager, which then sends a message to the delegate.

+2
source

First, the documentation does not indicate that onlyAccuracy determines how far you are in the region before the ExExitRegion event is raised. If you want to fine-tune how often events fire, you also need to use distanceFilter, which determines the horizontal movement that needs to be moved before the event fires.

If using distanceFilter does not work, I would recommend the following:

  • If you are using NSNotificationCenter, be sure to remove other classes from the notification using [[NSNotificationCenter defaultCenter] removeObserver: self]. You can specify a name and object for this call.

  • 1000 km is a large radius that has a high probability of crossing with many regions in the vicinity. I would try a lower number for this parameter to find out if the number of exit notifications you receive is decreasing. The only thing that indicates that this may not be the solution is that you did not say that you received didEnterRegion blasts.

  • Finally, I would check the CLRegion identifier that was passed to didExitRegionEvent to make sure that you cannot create NSDictionary regions yourself. You will need to set the region to the dictionary on didEnterRegion and delete it on didExitRegion. So, at didExitRegion all you have to do is make sure that you are interested in the region by checking that you already have the region. I would suggest that CLRegion is already equipped with isEqual: and a hash so that it can be stored in the collection.

Good luck

0
source

I found that to save battery you should use monitorForSignificantLocationChange . My solution is to filter out multiple alerts within 60 seconds for the same region:

 -(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
source

Source: https://habr.com/ru/post/908586/


All Articles