There are a lot of glamorous iBeacon problems out there. This post doesn’t contain any of them. Instead, this is a post about two embarrassingly simple errors and how I fixed them.
Your CLLocationManager Must Be Recreated When You Return from Backgrounding
I read the documentation for
CLLocationManager and its delegate methods, implemented them, and then thought I was done. Unfortunately, hidden away in the documentation for a related class,
CLRegion, is something important (emphasis mine):
If the app is not running when a boundary crossing occurs, the system launches the app into the background to handle it. Upon launch, your app must configure new location manager and delegate objects to receive the notification. The notification is sent to your delegate’s locationManager:didEnterRegion: method.
My application was launching in the background correctly, but I wasn’t configuring a new location manager and delegate objects whenever the application launched. It’s a quick fix, and it makes sense in retrospect, but that note isn’t where I would expect to find it in the documentation.
CLRegion Doesn’t Notify When Individual Beacons Change
CLRegion can contain zero or more beacons using the same UUID. While the
didEnterRegion delegate method is called as soon as it spots a single beacon, the
didExitRegion method is only called when there are no more beacons in range that match the region’s UUID. Don’t confuse
didExitBeaconRange (which doesn’t exist) or you’ll wear a hole in your floor running back and forth between rooms trying to figure out why your app is never notified.1
If you need to detect when you’ve left the range of one particular beacon, you need to actively scan for beacons (battery intensive) or give each beacon a different UUID so you can create and monitor multiple