如何在不阻塞代码的情况下等待BLE回调

时间:2019-05-29 12:38:15

标签: ios swift multithreading bluetooth-lowenergy

我正在尝试在两个BLE设备之间交换数据。实际上客户端是功能正常的,而我的问题出在IOS手机的服务器端。 我创建了一个从NSObject和CBPeripheralManagerDelegate继承的BluetoothLEController。服务,广告,连接,订阅和didReceiveWrite的所有部分均有效。

这是我的问题,当我同时两次或更多次调用CBPeripheralManager类的updateValue方法时,只有第一次调用成功。在Swift文档中,如果发送队列繁忙,则此函数返回false。 我编写了这样的伪无限循环

while !peripheralManager.updateValue(data,
                                     for: messageContentCharacteristic,
                                     onSubscribedCentrals: nil) {}

它可以工作,但实现起来确实很糟糕!

所以在那之后我尝试使用DispatchSemaphore

let semaphore = DispatchSemaphore(value: 1)
func write(_ data: Data) {
    DispatchQueue.global().async {
        self.semaphore.wait()
        self.peripheralManager.updateValue(data,
                                           for: self.messageContentCharacteristic,
                                           onSubscribedCentrals: nil)
    }
}

func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
    semaphore.signal()
}

所有线程正在运行。第一个电话updateValue和我的客户收到通知。另一个正在等待。 但是,从未调用回调peripheralManagerIsReady#toUpdateSubscribers并且我的应用程序被阻止了。

我正在尝试使用具有其他优先级的DispatchGroup和DispatchQueue进行其他方式,但是我的问题仍然相同。

我希望有人可以帮助我成为更好的开发者:)

1 个答案:

答案 0 :(得分:0)

正如Paulw11所说,我实现了一个基于Swift算法俱乐部的通用队列。我坚决使用我的信号量,但仅出于线程安全。

let queue = Queue<Data>()
let semaphore = DispatchSemaphore(value: 1)

func write(_ data: Data) {
    if !peripheralManager.updateValue(data,
                                  for: messageContentCharacteristic,
                                  onSubscribedCentrals: nil) {
        semaphore.wait()
        queue.enqueue(data)
        semaphore.signal()
    }
}

func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) {
    if !queue.isEmpty {
        semaphore.wait()
        if let data = queue.dequeue() {
            peripheralManager.updateValue(data,
                                          for: messageContentCharacteristic,
                                          onSubscribedCentrals: nil)
        }
        semaphore.signal()
    }
}