我正在尝试设置客户端的应用程序以在 iOS 设备到达/离开办公室时触发数据库更新。
(这是一个供我客户的销售人员在现场使用的应用程序,其中一些客户站点没有任何网络连接,因此客户希望在销售人员离开办公室/返回办公室时更新数据库。)
我从不接听didEnterRegion
或didExitRegion
打电话。
我有一个RegionsManager
管理位置管理器实例的单例。我正在使用CLLocationManager
和startMonitoringForRegion
方法。
在启动时,我调用RegionsManager
创建位置管理器并将自己设置为位置管理器的委托。
在我的应用程序委托的didFinishLaunchingWithOptions
方法中,我检查了UIApplicationLaunchOptionsLocationKey
,以防我因进入/退出的区域而重新启动,但这永远不会发生。
我NSLocationAlwaysUsageDescription
在 info.plist 中有一个键/值对。
我打电话CLLocationManager.authorizationStatus
以确保该应用程序被授权,如果没有,我打电话给requestAlwaysAuthorization
.
一旦我验证了应用程序已获得授权,我还会检查 isMonitoringAvailableForClass(CLCircularRegion)。
假设监控可用,然后我检查位置管理器的集合是否monitoredRegions
已经包含我将要创建的区域(我只是检查坐标)。如果是这样,我跳过添加区域。
如果位置管理器尚未监控该区域,我将调用添加到startMonitoringForRegion
.
在应用程序的第二次启动时,我在位置管理器的集合中看到了我在上次启动时添加的区域monitoredRegions
,因此我知道它们正在被添加。
设置所有这些的代码非常复杂,因为它被设置为处理添加多个区域,并且还具有维护被监视区域数组的逻辑,以及一个应该在 on a didEnterRegion
ordidExitRegion
消息时调用的块。
这是(相当长的)完整的有问题的方法:
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)
}
regionsBeingMonitored
我的 RegionsManager 类有一个对象数组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
my or的方法签名didExitRegion
看起来是正确的,所以我认为不是这样。