如何监控多个 iBeacon 并根据每个信标更改 UILabel?



我在同时监控多个信标时遇到问题.我的代码只用一个就可以正常工作, 但我似乎无法弄清楚如何监控多个信标并更新 UILabel.

当我打开信标时,信标都会受到监控和识别, 但我的手机无法在视图中显示正确的标签.它不断在距离中显示"UNKOWN"阅读.text,除非它是函数中的最后一个信标(Estimote)。

我还遇到了一些其他问题,即更新信标的名称.我不确定如何调用信标标识符, 这将是理想的方式 (像信标.标识符).我尝试创建另一个变量并通过每个信标扫描更新名称, 但它只是扫描最后一个并且不会改变.我希望它在检测到时会扫描它, 从而允许我在检测到新信标时更改变量.

我尝试将所有信标放在一个startScanning()函数中,为每个唯一的UUID提供变量,并对每个单独的信标使用locationManager.startMonitoring()和locationManager.startRangingBeacon()。然后我尝试使用每个 UUID、主要、次要和标识符的参数创建一个 startScanning() 函数,然后为每个信标调用该函数。

class ViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet var distanceReading: UILabel!
@IBOutlet var nameLabel: UILabel!
var locationManager: CLLocationManager?
var beaconDict: [String: String]?
var labelName: String?
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestAlwaysAuthorization()
alertShown = false
view.backgroundColor = .gray  // default is in "unknown mode"
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
// Can we monitor beacons or not?
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
//  Can we detect the distance of a beacon?
if CLLocationManager.isRangingAvailable() {
startScanning(uuid: UUID(uuidString: "5A4BCFCE-174E-4BAC-A814-092E77F6B7E5")!, major: 123, minor: 456, identifier: "Apple Beacon", name: "Apple")
startScanning(uuid: UUID(uuidString: "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6")!, major: 123, minor: 456, identifier: "Radius Beacon", name: "Radius")
startScanning(uuid: UUID(uuidString: "5AFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")!, major: 123, minor: 456, identifier: "Red Bear Beacon", name: "Red Bear")
startScanning(uuid: UUID(uuidString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D")!, major: 123, minor: 456, identifier: "Estimote", name: "Estimote")
}
}
}
}
func startScanning(uuid: UUID, major: UInt16, minor: UInt16, identifier: String, name: String) {
let uuidApple = uuid
let beaconRegion1 = CLBeaconRegion(proximityUUID: uuidApple, major: major, minor: minor, identifier: identifier)
locationManager?.startMonitoring(for: beaconRegion1)
locationManager?.startRangingBeacons(in: beaconRegion1)
labelName = name
}
func update(distance: CLProximity) {
UIView.animate(withDuration: 1) {
switch distance {
case .far:
self.view.backgroundColor = .blue
self.distanceReading.text = "FAR"
case .near:
self.view.backgroundColor = .orange
self.distanceReading.text = "NEAR"
case .immediate:
self.view.backgroundColor = .red
self.distanceReading.text = "RIGHT HERE"
default:
self.view.backgroundColor = .gray
self.distanceReading.text = "UNKNOWN"
}
}
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if let beacon = beacons.first {
nameLabel.text = labelName
update(distance: beacon.proximity)
} else {
update(distance: .unknown)
}
}

我希望每次检测到新信标时, 我的标签会相应地改变.这适用于名为 LAST 的信标, 但不是前三个.颜色会改变,但标签拒绝改变。我还想找出一种方法来调用我在 CLBeaconRegion 中设置的信标标识符.

尝试像for beacon in beacons一样遍历所有远程信标,而不是像beacons.first那样只使用数组中的第一个信标。

信标名称的问题是labelName是一个字符串,并且您在startScanning中设置了其值。每次调用时,startScanning都会覆盖以前的值labelName。自上次调用startScanning以来,您提供了名称Estimote,这是您将始终在nameLabel中看到的值。

您有一个beaconDict属性,表明您可能一直在考虑此问题,但没有继续。

我要做的是创建一个Beacon结构来保存信标的所有属性,包括其name,创建此结构的实例以传递给startScanning并将这些实例存储在[String:Beacon]字典中。使用 UUID 的字符串作为键。然后, 我们收到回电,您可以使用信标标识符从字典中查找相应的Beacon并获取其name.

至于为什么距离总是未知的,大卫是对的;你将在didRangeBeacons回调中收到4个信标。由于您只有一个物理信标,因此除了您当前处于活动状态的信标之外,所有信标都将是未知的, 但您只看第一个.

您可能会发现使用每个信标一行的表视图比使用单个标签更容易.