How to Monitor More Than 20 Regions

How to monitor more than 20 regions?

set currentLocation from your didUpdateLocations

var currentLocation : CLLocation?{
didSet{
evaluateClosestRegions()
}
}

var allRegions : [CLRegion] = [] // Fill all your regions

Now calculate and find the closest regions to your current location and only track those.

func evaluateClosestRegions() {

var allDistance : [Double] = []

//Calulate distance of each region's center to currentLocation
for region in allRegions{
let circularRegion = region as! CLCircularRegion
let distance = currentLocation!.distance(from: CLLocation(latitude: circularRegion.center.latitude, longitude: circularRegion.center.longitude))
allDistance.append(distance)
}
// a Array of Tuples
let distanceOfEachRegionToCurrentLocation = zip(allRegions, allDistance)

//sort and get 20 closest
let twentyNearbyRegions = distanceOfEachRegionToCurrentLocation
.sorted{ tuple1, tuple2 in return tuple1.1 < tuple2.1 }
.prefix(20)

// Remove all regions you were tracking before
for region in locationManager.monitoredRegions{
locationManager.stopMonitoring(for: region)
}

twentyNearbyRegions.forEach{
locationManager.startMonitoring(for: $0.0)
}

}

To avoid having the didSet called too many times, I suggest you set the distanceFilter appropriately (not too big so you would catch the region's callbacks too late and not too small so that you won't have redundant code running). Or as this answer suggests, just use startMonitoringSignificantLocationChanges to update your currentLocation

Need to get more than 20 notification for Region Monitoring

  1. Have an NSMutableArray with all the regions you want to monitor +20.
  2. Listen to significant location updates.
  3. When you get a location update, if the NSMutableArray of all your regions is more than 20 then stop monitoring all regions been monitored and calculate the 20 nearest regions using the harvesine formula:

Harvesine - Objective C

Harvensine - Swift

That will give you the distance between the two locations. After that you could compare that distance with the region radius to know if is inside the region.

Note: This distance will be in kilometers if your radius is on meters then just multiply the haversine method result with 1000 so that it's converted to meters.


  1. Start monitoring the result list of the 20 nearest regions.

This will allow you to always monitor the 20 nearest regions based on your location. Been able to monitor more than 20 since it will change the monitoring regions always to the 20 nearest regions.

Does the location manager's limit of 20 regions mean 20 total geofence AND beacon regions?

Yes, the 20 region limit is the maximum that CoreLocation lets you monitor for both CLBeaconRegions and CLCircularRegions (geofences) combined. When iOS 7 added beacon support, beacon regions inherited this same limitation for geofences because of the ways the APIs were defined. And as you suspected, the limit applies to any type of region you want to monitor. So you can monitor 10 CLBeaconRegions and 10 CLCircularRegions but no more than 20 combined of each type.

how to startMonitoringForRegion for more then 20 region

You just can't monitor more than 20 regions. Maybe you could stop monitoring some regions depending on user location and start some others (depending on your use case).

Discussion You must call this method once for each region you want to
monitor. If an existing region with the same identifier is already
being monitored by the application, the old region is replaced by the
new one. The regions you add using this method are shared by all
location manager objects in your application and stored in the
monitoredRegions property.

Region events are delivered to the locationManager:didEnterRegion: and
locationManager:didExitRegion: methods of your delegate. If there is
an error, the location manager calls the
locationManager:monitoringDidFailForRegion:withError: method of your
delegate instead.

An app can register up to 20 regions at a time. In order to report
region changes in a timely manner, the region monitoring service
requires network connectivity.

In iOS 6, regions with a radius between 1 and 400 meters work better
on iPhone 4S or later devices. (In iOS 5, regions with a radius
between 1 and 150 meters work better on iPhone 4S and later devices.)
On these devices, an app can expect to receive the appropriate region
entered or region exited notification within 3 to 5 minutes on
average, if not sooner.

https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringForRegion:

iOS region monitoring, to monitor more than 20 locations

This is actually Apple's suggestion Core Location Programming Guide:

To work around this limit, consider registering only those regions in
the user’s immediate vicinity. As the user’s location changes, you can
remove regions that are now farther way and add regions coming up on
the user’s path.

However, it's not clear how much time you get when didEnterRegion: is called in the background, so it's not clear if you have time to make a server call if running the background. The "significant-change location service" information says:

If you leave the significant-change location service running and your
iOS app is subsequently suspended or terminated, the service
automatically wakes up your app when new location data arrives. At
wake-up time, the app is put into the background and you are given a
small amount of time (around 10 seconds) to manually restart location
services and process the location data.... Because your app is in the
background, it must do minimal work and avoid any tasks (such as
querying the network) that might prevent it from returning before the
allocated time expires
. If it does not, your app will be terminated.
If an iOS app needs more time to process the location data, it can
request more background execution time using the
beginBackgroundTaskWithName:expirationHandler: method of the
UIApplication class.

You could try the combination of region monitoring, making a server call in didEnterEter region and then calling beginBackgroundTaskWithName:expirationHandler: to make sure you have enough time. The combination of region monitoring + server calls + background processing is going to hit battery life, though.

EDIT: You could also create "mega regions" of a large area that contain many smaller regions. When the user enters those mega regions, set up and add all the smaller regions you are interested in, and when they exit, remove them.



Related Topics



Leave a reply



Submit