Почему я не получаю вызовы didEnterRegion или didExitRegion при использовании startMonitoringForRegion из CLLocationManager
Я пытаюсь настроить клиентское приложение для запуска обновления базы данных, когда устройство iOS прибывает / покидает офис.
(Это приложение, которое продавцы моего клиента могут использовать в полевых условиях, где некоторые сайты клиентов не имеют сетевого подключения, поэтому клиент хочет обновить базу данных, когда продавцы покидают офис / возвращаются в офис.)
Я никогда не получаю didEnterRegion
или же didExitRegion
звонки.
У меня есть синглтон RegionsManager
который управляет экземпляром менеджера местоположения. я использую CLLocationManager
и startMonitoringForRegion
метод.
На запуске я призываю RegionsManager
который создает менеджер местоположения и устанавливает себя как делегат менеджера местоположения.
В моем приложении делегат didFinishLaunchingWithOptions
метод, который я проверяю для UIApplicationLaunchOptionsLocationKey
на случай, если меня перезапустят для региона, в который можно войти / выйти, но этого никогда не произойдет.
у меня есть NSLocationAlwaysUsageDescription
пара ключ / значение в info.plist.
Я звоню CLLocationManager.authorizationStatus
чтобы убедиться, что приложение авторизовано, и если нет, я звоню requestAlwaysAuthorization
,
Как только я проверяю, что приложение авторизовано, я также проверяю isMonitoringAvailableForClass(CLCircularRegion).
Предполагая, что мониторинг доступен, я затем проверяю, установлен ли monitoredRegions
уже содержит регион, который я собираюсь создать (я просто проверяю координаты). Если так, я пропускаю добавление региона.
Если менеджер местоположения еще не контролирует регион, я добавляю его с вызовом startMonitoringForRegion
,
При втором запуске приложения я вижу регионы, которые я добавил при последнем запуске, в наборе диспетчера местоположений monitoredRegions
, так что я знаю, что они добавляются.
Код для установки всего этого достаточно сложен, поскольку он настроен на обработку добавления нескольких областей, а также имеет логику для поддержки массива отслеживаемых областей и блока, который должен вызываться, если на didEnterRegion
или же didExitRegion
сообщение.
Вот этот метод в целом (довольно долго):
func startMonitoring(#coordinate: CLLocationCoordinate2D,
radius: CLLocationDistance = regionDistance,
id: String = "",
notificationBlock: regionNotificationBlock)
{
var authorizationStatus = CLLocationManager.authorizationStatus()
if !locationManagerReady
{
//Make sure we're authorized to use the location manager.
if authorizationStatus == .NotDetermined && !waitingForAuthorization
{
//We haven't been authorized yet. Trigger a prompt to the user.
theLocationMgr.requestAlwaysAuthorization()
waitingForAuthorization = true
authorizationStatus = CLLocationManager.authorizationStatus()
}
//Wait for the user to grant/deny permission.
if authorizationStatus == .NotDetermined
{
//After 1 second, re-call this method to try again.
delay(1.0)
{
()-> () in
self.startMonitoring(
coordinate: coordinate,
radius: radius,
id: id,
notificationBlock: notificationBlock)
}
return
}
let rootVC: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController
if authorizationStatus == CLAuthorizationStatus.Restricted ||
authorizationStatus == CLAuthorizationStatus.Denied
{
Utils.showAlertOnVC(
rootVC,
title: "Location manager error",
message: "Permission to access location denied")
return
}
else if !CLLocationManager.isMonitoringAvailableForClass(CLCircularRegion)
{
Utils.showAlertOnVC(
rootVC,
title: "Location manager error",
message: "geofencing is not available.")
return
}
}
if !locationManagerReady
{
locationManagerReady = true
theLocationMgr.desiredAccuracy = kCLLocationAccuracyBest
theLocationMgr.distanceFilter = kCLDistanceFilterNone;
}
//If we get here, we're done configuring the location manager
//If this region is already in our array of regions, don't add it again.
if let existingRegionIndex = regionIndexForCoordinate(coordinate)
{
return
}
let regionToMonitor = CLCircularRegion(
center: coordinate,
radius: radius,
identifier: id)
//See if the system is still monitoring this region from a previous launch.
var found = false
var foundRegion: CLCircularRegion? = nil
if let monitoredRegions = theLocationMgr.monitoredRegions as NSSet?
{
let regionsArray = monitoredRegions.allObjects as NSArray
let regionIndex = regionsArray.indexOfObjectPassingTest()
{ (object, index, flag) -> Bool in
if let region = object as? CLCircularRegion
{
return region.center.latitude == coordinate.latitude &&
region.center.longitude == coordinate.longitude
}
else
{
return false
}
}
found = regionIndex != NSNotFound
if found
{
foundRegion = regionsArray[regionIndex] as? CLCircularRegion
}
}
if found
{
logToFile("already monitoring (\(coordinate.latitude),\(coordinate.longitude)). ID = '\(foundRegion!.identifier!)'")
}
else
{
logToFile("Adding geofence for (\(coordinate.latitude),\(coordinate.longitude)). ID = '\(id)'")
theLocationMgr.startMonitoringForRegion(regionToMonitor)
}
let aRegionEntry = RegionEntry(region: regionToMonitor, regionNoticeBlock: notificationBlock)
regionsBeingMonitored.append(aRegionEntry)
}
Мой класс RegionsManager имеет массив regionsBeingMonitored
из RegionEntry
объекты:
lazy var regionsBeingMonitored = [RegionEntry]()
Вот объект RegionEntry:
class RegionEntry: NSObject
{
var theRegion: CLCircularRegion?
var theRegionNoticeBlock: regionNotificationBlock?
init(region: CLCircularRegion?, regionNoticeBlock: regionNotificationBlock?)
{
theRegion = region
theRegionNoticeBlock = regionNoticeBlock
}
}
У этого также есть флаги состояния, чтобы отследить настройку менеджера местоположения:
var waitingForAuthorization: Bool = false
var locationManagerReady: Bool = false
Я внимательно изучил документацию по настройке мониторинга региона и уверен, что выполняю все настройки, которые я должен делать.
Мои методы didEnterRegion и didExitRegion записывают сообщение в файл журнала, как только они вызываются, так что даже если в моей логике есть проблема с сопоставлением региона с записью в моем regionsBeingMonitored
массив я все еще должен увидеть запись в журнале:
func locationManager(manager: CLLocationManager!,
didEnterRegion region: CLRegion!)
{
logToFile("In \(__FUNCTION__). region = \(region)")
if let region = region as? CLCircularRegion
{
if let regionIndex = regionIndexForCoordinate(region.center)
{
let aRegionEntry = regionsBeingMonitored[regionIndex]
aRegionEntry.theRegionNoticeBlock?(region: region, didEnter: true)
}
}
}
func locationManager(manager: CLLocationManager!,
didExitRegion region: CLRegion!)
{
logToFile("In \(__FUNCTION__). region = \(region)")
if let region = region as? CLCircularRegion
{
if let regionIndex = regionIndexForCoordinate(region.center)
{
let aRegionEntry = regionsBeingMonitored[regionIndex]
aRegionEntry.theRegionNoticeBlock?(region: region, didEnter: false)
}
}
}
Вы видите что-нибудь, что я могу делать неправильно? Подпись метода для моего didEnterRegion
или же didExitRegion
выглядит правильно, так что я не думаю, что это все.