ios - 等待 iOS Swift CBPeripheralDelegate 完成的正确方法?
问题描述
在进行蓝牙通信时,通常会遇到这样一种情况,即进行调用并在委托中获得响应,例如如下所示的特征发现:
func discoverCharacteristics(device: CBPeripheral)
{
servicesCount = device.services!.count
for service in device.services!
{
print("Discovering characteristics for service \(service.uuid)")
device.discoverCharacteristics([], for: service)
}
}
现在,此发现不是针对特定设备,而是针对遵循蓝牙 SIG 服务/配置文件的健康设备,因此我不确切知道它们可能具有哪些服务,也不知道每个服务中可能有多少特征。该方法是异步的,答案在以下委托方法中发出信号:
// Discovered Characteristics event
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
for characteristic in service.characteristics!
{
print("Found characteristic \(characteristic.uuid)")
}
servicesCount = servicesCount - 1;
print("Characteristics sets left: \(servicesCount)")
if servicesCount == 0
{
print ("Found all characteristics")
DispatchQueue.main.async{
self.btleManager!.btleManagerDelegate.statusEvent(device: peripheral, statusEvent: Btle.CHARACTERISTICS_DISCOVERED)
}
self.device = peripheral
self.handleMds()
}
}
现在我需要等到发现完成后才能进行下一步,因为我下一步做什么通常取决于我得到了什么。在 Java 和 Android 中,我所做的是在调用方法中等待 CountDownLatch,然后我在回调中向锁存器发出信号以释放该等待。
CountDownLatch 的 iOS 等效项似乎是 DispatchSemaphore。但是,这样做显然会阻塞系统,并且不会调用任何委托。所以我所做的(如上面的代码所示)是servicesCount
用服务数量初始化一个变量,并在每次发出信号时在委托回调中递减它。当它变为零时,我就完成了,然后我进行下一步。
这种方法有效,但看起来很老套;它不可能是正确的。当我需要对 DIS 特性、功能、各种时间服务等进行多次读取时,它开始变得非常混乱。 所以我想知道什么是等待代表发出信号的正确方法在前进之前?回想一下,我不知道这些设备可能具有哪些服务或特性。
解决方案
首先,如果您已经为 Android 实现了 CountDownLatch,您可以为 iOS 执行相同的实现。是的,Swift 没有内置的CountDownLatch
,但是来自 Uber的好人创造了一个很好的实现。
另一种选择是依赖一个变量,就像你做的那样,但是让它成为原子的。网上有多种实现,包括同一个 Uber 库中的一种。另一个例子是在RxSwift 库中。还有许多其他变体。原子变量将为变量的读/写操作提供线程安全。
但可能最快捷的方法是拥有一个 DispatchGroup。看起来像这样:
let dispatchGroup = DispatchGroup() // instance-level definition
// ...
func discoverCharacteristics
{
for service in device.services!
{
dispatchGroup.enter()
// ...
}
dispatchGroup.notify(queue: .main) {
// All done
print ("Found all characteristics")
DispatchQueue.main.async{
self.btleManager!.btleManagerDelegate.statusEvent(device: peripheral, statusEvent: Btle.CHARACTERISTICS_DISCOVERED)
}
self.device = peripheral
self.handleMds()
}
// ...
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
// ...
dispatchGroup.leave()
}
换句话说,您在即将提交请求时进入组,在处理请求时离开。当所有项目离开组时,notify
将使用您提供的块执行。
推荐阅读
- terminal - 是否可以在 macOS 终端中获取文件所有者 url 元数据?
- git - git svn fetch '错误运行上下文:软件导致连接中止...'
- python - Python:将 .txt 文件加载到不同的列表中
- postgresql - Postgres 更新 JSON 列中所有记录的第一条记录
- javascript - 未捕获的 DOMException:无法在“文档”上执行“querySelector”:“#”不是有效的选择器
- c - 我可以打开一个伪终端作为奇校验吗?我不断重新调整无效参数
- javascript - 如何使用 Javascript 通过 selenium 3.6.0 使用另一个配置文件打开 Firefox 浏览器
- angular - 淡入和推底动画
- gitlab - .gitlab-ci.yml 中的条件 after_script
- hyperledger-fabric - 卸载 Hyperledger-composer 后出现 npm 安装错误 - 区块链