1

我正在尝试设置客户端的应用程序以在 iOS 设备到达/离开办公室时触发数据库更新。

(这是一个供我客户的销售人员在现场使用的应用程序,其中一些客户站点没有任何网络连接,因此客户希望在销售人员离开办公室/返回办公室时更新数据库。)

我从不接听didEnterRegiondidExitRegion打电话。

我有一个RegionsManager管理位置管理器实例的单例。我正在使用CLLocationManagerstartMonitoringForRegion方法。

在启动时,我调用RegionsManager创建位置管理器并将自己设置为位置管理器的委托。

在我的应用程序委托的didFinishLaunchingWithOptions方法中,我检查了UIApplicationLaunchOptionsLocationKey,以防我因进入/退出的区域而重新启动,但这永远不会发生。

NSLocationAlwaysUsageDescription在 info.plist 中有一个键/值对。

我打电话CLLocationManager.authorizationStatus以确保该应用程序被授权,如果没有,我打电话给requestAlwaysAuthorization.

一旦我验证了应用程序已获得授权,我还会检查 isMonitoringAvailableForClass(CLCircularRegion)。

假设监控可用,然后我检查位置管理器的集合是否monitoredRegions已经包含我将要创建的区域(我只是检查坐标)。如果是这样,我跳过添加区域。

如果位置管理器尚未监控该区域,我将调用添加到startMonitoringForRegion.

在应用程序的第二次启动时,我在位置管理器的集合中看到了我在上次启动时添加的区域monitoredRegions,因此我知道它们正在被添加。

设置所有这些的代码非常复杂,因为它被设置为处理添加多个区域,并且还具有维护被监视区域数组的逻辑,以及一个应该在 on a didEnterRegionordidExitRegion消息时调用的块。

这是(相当长的)完整的有问题的方法:

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)
    }
  }
}

你看到我可能做错了什么吗?didEnterRegionmy or的方法签名didExitRegion看起来是正确的,所以我认为不是这样。

4

0 回答 0