我以开源 Bluefruit 代码为例,特别是 BleManager 类,它是与 CBCentralManager 的接口(interface)。我已经给作者发了邮件,他们没有回复:
Bluefruit BleManager class
看起来该类是在单例体系结构中设计的(第 23 行的“共享”),因此在代码中的其他地方调用第一个“BleManager.connect()”时是懒惰地构造的。
让我感到困惑的是在 init() 中,有一个信号量“等待”函数:
override init() {
super.init()
centralManagerPoweredOnSemaphore.wait()
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.global(qos: .background), options: [:])
// centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main, options: [:])
}
我真的只习惯于 DispatchQueue.async() 线程中的信号量。这个 wait() 函数不是在主线程上调用的吗?不会锁了吧?将取消阻塞 .wait() 调用的 .signal() 调用位于第 289 行:extension BleManager: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
DLog("centralManagerDidUpdateState: \(central.state.rawValue)")
// Unlock state lock if we have a known state
if central.state == .poweredOn || central.state == .poweredOff || central.state == .unsupported || central.state == .unauthorized {
centralManagerPoweredOnSemaphore.signal()
}
因此,一旦系统 centralManager 更新了 BLE 实用程序状态,就会调用它,只要它不是未知的,就会调用 .signal() 并且 init() 的其余部分将运行。我已经使用打印语句来确认它是如何工作的。调用 centralManagerPoweredOnSemaphore.wait(),然后调用 centralManagerDidUpdateState(),然后调用其余的 init()。我仍然不明白这一点:最后它仍然有效,我只是想知道事情的确切顺序实际上是如何在引擎盖下运行以使其正常运行的。
最佳答案
他们正在使用信号量来阻止 BleManager
上的任何操作。对象直到中央退出 .unknown
状态。
信号量的初始值为 1。wait
在 init
将其递减为 0,而不是阻塞。然后初始化中央,并在某些时候进入通电状态。此时signal
将信号量返回到 1。
现在查看其他函数,例如 connect
函数(第 167 行)你会看到他们做的第一件事是 wait
然后 signal
信号量。考虑在两种不同的状态下会发生什么:
.poweredOn
state - 信号量计数为 0,所以 wait
block 。假设 BLE 状态变为 .poweredOn
在某些时候,wait
将结束并立即释放信号量,然后 connect
函数进行。 .poweredOn
state - 信号量计数为 1,所以 wait
不阻塞,然后立即释放信号量,connect
函数进行。 其他功能以类似的方式工作。
这种方法的优点是调用代码不需要一直检查状态;它可以访问
sharedInstance
然后立即调用startScan
无需检查 Central 是否已打开电源。
关于iOS Swift - 关于蓝牙低功耗管理器中的信号量和排序的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64528143/