Как я могу отслеживать несколько iBeacon и изменять UILabel для каждого маяка?

У меня проблема с одновременным мониторингом нескольких маяков. Мой код отлично работает только с одним, но я не могу понять, как отслеживать более одного маяка И обновлять UILabel.

Все маяки отслеживаются и распознаются, когда я их включаю, но мой телефон не отображает правильные метки в обзоре. Он постоянно показывает "UNKOWN" в distanceReading.text, если только это не последний маяк в функции (Estimote).

У меня также есть некоторые другие проблемы с обновлением имени, для которого это маяк. Я не уверен, как вызвать идентификатор маяка, что было бы идеальным способом (что-то вроде beacon.identifier). Я пробовал создать другую переменную и обновлять имя при каждом сканировании маяка, но он просто сканирует последнюю и не меняется. Я надеялся, что он просканирует его, КОГДА он был обнаружен, что позволило мне изменить переменную при обнаружении нового маяка.

Я попытался поместить все маяки в одну функцию startScanning (), присвоив каждому уникальному UUID его переменной и используя locationManager.startMonitoring () и locationManager.startRangingBeacon () для каждого отдельного маяка. Затем я попытался создать функцию startScanning (), используя параметры для каждого UUID, основного, второстепенного и идентификатора, а затем вызвать функцию для каждого маяка.

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

Я ожидаю, что каждый раз, когда будет обнаружен новый маяк, моя метка будет соответственно меняться. Это работает так, как предназначено для маяка с именем ПОСЛЕДНИЙ, но не для первых трех. Цвет меняется, но этикетка не меняется. Я также хотел бы найти способ вызвать идентификатор маяка, который я установил в CLBeaconRegion.


person Thomas Kellough    schedule 10.07.2019    source источник


Ответы (2)


Попробуйте перебрать все дальномеры, как в for beacon in beacons, вместо того, чтобы просто работать с первым в массиве, как в beacons.first.

person davidgyoung    schedule 10.07.2019
comment
Я думал об этом, но не знаю, как бы это проверить. Прямо сейчас я использую приложение маяка, чтобы проверить это, поэтому я могу активировать только один маяк за раз (только одно дополнительное устройство). Однако я до сих пор не знаю, решит ли это проблему, потому что, когда я печатаю (маяк) после проверки beacon == beacon.first, он всегда будет печатать правильную информацию о маяке. Он просто не может правильно обновить distanceReading.text (если это не последний маяк) в моем операторе switch. Если это один из первых трех маяков, он просто показывает НЕИЗВЕСТНО. - person Thomas Kellough; 10.07.2019

Ваша проблема с именем маяка в том, что labelName - это одна строка, и вы устанавливаете ее значение в startScanning. Каждый раз при вызове startScanning вы перезаписываете предыдущее значение labelName. С момента последнего вызова startScanning вы указываете имя Estimote, это значение, которое вы всегда будете видеть в nameLabel.

У вас есть свойство beaconDict, которое показывает, что вы, возможно, думали об этом, но не продолжили.

Я бы создал структуру Beacon для хранения всех свойств маяка, включая его name, создал экземпляры этой структуры для передачи startScanning и сохранил эти экземпляры в словаре [String:Beacon]. Используйте строку UUID в качестве ключа. Затем вам перезвонят, и вы можете использовать идентификатор маяка, чтобы найти соответствующий Beacon из словаря и получить его name.

Что касается того, почему расстояние всегда неизвестно, Дэвид прав; вы получите 4 маяка в обратном вызове didRangeBeacons. Поскольку у вас есть только один физический маяк, все маяки, кроме того, который у вас сейчас активен, будут неизвестны, но вы смотрите только на первый.

Вероятно, вам будет проще использовать табличное представление с одной строкой на маяк, чем с одной меткой.

person Paulw11    schedule 10.07.2019
comment
Я пришел к такому же выводу, что и вы, по вопросу nameLabel. И вы правы, я попробовал словарь и потерпел неудачу. Я еще не пробовал настраивать структуру, я должен был подумать об этом! Тогда это может упростить мой словарь и решить проблему с идентификатором. Я думаю, что это еще не все, о списке маяков. У меня активен только один маяк, поэтому только первый маяк всегда является единственным маяком. И расстояние действительно работает, или, по крайней мере, цветовая составляющая. Это просто ярлык, который не обновляется с неизвестного, хотя, возможно, вышеуказанное решение все же исправит это! - person Thomas Kellough; 11.07.2019
comment
когда вы получаете обновление для неактивного маяка, вы меняете текст, но не цвет, поэтому вы всегда видите неизвестное. Было показано расстояние до активного маяка, но оно было быстро заменено неактивным маяком. Добавьте оператор печати при установке текста расстояния, и вы увидите, что происходит. Опять же, табличное представление упростит это - person Paulw11; 11.07.2019
comment
Ладно, думаю, понимаю. Я попробую и посмотрю, что будет! Спасибо за ваши предложения! Я дам вам знать, если это сработает! - person Thomas Kellough; 11.07.2019
comment
Спасибо за помощь. У меня все заработало. Не знаю, лучший ли это способ, но я все еще учусь. Я создал структуру Beacon для хранения всех свойств маяка, создал массив [Beacon] (моя структура), а затем зациклил startScanning () над ними. Я удалил оператор else в диспетчере местоположения (чтобы остановить обновление .unknown), затем сопоставил метку моего имени со структурным идентификатором. В будущем я, вероятно, изучу табличные представления для этого, но я просто хотел закончить это руководство, не меняя его сейчас слишком сильно! Спасибо вам и Дэвиду за вашу помощь! - person Thomas Kellough; 11.07.2019