找到最近的灯塔的正确方法

时间:2015-10-10 04:23:23

标签: ios iphone xcode swift ibeacon

当调用didRangeBeacons方法时,最近的beacon beacons.first?或者它是具有最低准确度值的信标列表中的信标?两个都正确吗?感谢

2 个答案:

答案 0 :(得分:1)

虽然didRangeBeacons:inRegion:回调中的信标列表按精度字段排序(实际上是以米为单位测量距离),但依赖此问题存在许多问题:

  • 如果在过去的第二天没有RSSI(信号强度)样本,有时信标的准确度值为-1。如果您继续进行自动排序,这会给您不正确的结果。

  • 如果在最后一秒内未检测到信标,则有时信标会从列表中删除。这是嘈杂的蓝牙环境中常见的问题,并且不常发送信标。

了解最近的信标的一种更健壮的方法是自己实现一种算法,该算法忽略精度值-1,并且能够容忍信标检测中的临时丢失(比如说5秒)。

当然,这只是一个开始。您可以通过添加各种其他过滤器来调整它,以便根据您的确切用例进行调整。没有过于复杂的事情,这里有一些我用于基础知识的Swift代码:

let expirationTimeSecs = 5.0
public var closestBeacon: CLBeacon? = nil
var trackedBeacons: Dictionary<String, CLBeacon>
var trackedBeaconTimes: Dictionary<String, NSDate>

override init() {
  trackedBeacons = Dictionary<String, CLBeacon>()
  trackedBeaconTimes = Dictionary<String, NSDate>()
}

public func locationManager(manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion) {
  let now = NSDate()
  for beacon in beacons {
    let key = keyForBeacon(beacon)
    if beacon.accuracy < 0 {
      NSLog("Ignoring beacon with negative distance")
    }
    else {
      trackedBeacons[key] = beacon
      if (trackedBeaconTimes[key] != nil) {
        trackedBeaconTimes[key] = now
      }
      else {
        trackedBeaconTimes[key] = now
      }
    }
  }
  purgeExpiredBeacons()
  calculateClosestBeacon()
}

func calculateClosestBeacon() {
  var changed = false
    // Initialize cloestBeaconCandidate to the latest tracked instance of current closest beacon
    var closestBeaconCandidate: CLBeacon?
    if closestBeacon != nil {
      let closestBeaconKey = keyForBeacon(closestBeacon!)
      for key in trackedBeacons.keys {
        if key == closestBeaconKey {
          closestBeaconCandidate = trackedBeacons[key]
        }
      }
    }

    for key in trackedBeacons.keys {
      var closer = false
      let beacon = trackedBeacons[key]
      if (beacon != closestBeaconCandidate) {
        if beacon!.accuracy > 0 {
          if closestBeaconCandidate == nil {
            closer = true
          }
          else if beacon!.accuracy < closestBeaconCandidate!.accuracy {
            closer = true
          }
        }
        if closer {
          closestBeaconCandidate = beacon
          changed = true
        }
      }
    }
    if (changed) {
      closestBeacon = closestBeaconCandidate
    }
}

func keyForBeacon(beacon: CLBeacon) -> String {
  return "\(beacon.proximityUUID.UUIDString) \(beacon.major) \(beacon.minor)"
}

func purgeExpiredBeacons() {
  let now = NSDate()
  var changed = false
  var newTrackedBeacons = Dictionary<String, CLBeacon>()
  var newTrackedBeaconTimes = Dictionary<String, NSDate>()
  for key in trackedBeacons.keys {
    let beacon = trackedBeacons[key]
    let lastSeenTime = trackedBeaconTimes[key]!
    if now.timeIntervalSinceDate(lastSeenTime) > expirationTimeSecs {
      NSLog("******* Expired seeing beacon: \(key) time interval is \(now.timeIntervalSinceDate(lastSeenTime))")
      changed = true
    }
    else {
      newTrackedBeacons[key] = beacon!
      newTrackedBeaconTimes[key] = lastSeenTime
    }
  }
  if changed {
    trackedBeacons = newTrackedBeacons
    trackedBeaconTimes = newTrackedBeaconTimes
  }
}

答案 1 :(得分:0)

一旦检测到信标,为了查看最接近的信标,您需要遍历locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region回调中的信标数组,并比较每个信标的准确属性。具有最低精度值的信标是最接近的。