iOS Swift - 关于蓝牙低功耗管理器中的信号量和排序的问题

标签 ios swift multithreading bluetooth bluetooth-lowenergy

我以开源 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()。我仍然不明白这一点:
  • 主线程上的信号量 .wait() 是如何没有锁定所有内容的?例如查看第 169 行和第 170 行。这是做什么的?
  • 尚未分配委托(delegate)时如何调用 centralManagerDidUpdateState() ?似乎委托(delegate)被分配在 init() 的底部,该函数在此函数之前没有立即调用。系统 CBCentralManager 如何知道使用特定的 centralManagerDidUpdateState() 函数?
  • CBCentralManager 状态究竟是如何工作的?我已通读 official documentation但它不是太具有描述性。似乎当"Core Bluetooth initializes or resets" it will be "unknown" .然后在一段时间后,它是否总是会根据设备是否具有能力以及用户设置/权限是什么而变为已知状态?所以我猜这就是为什么在我们得到回应之前阻止其他人是“安全的”。但是在这种情况下是什么“初始化”了核心蓝牙呢?据我所知,使用部分 init() 和在 centralManagerDidUpdateState() 之前,没有调用任何核心蓝牙功能。是什么让 Core Bluetooth 尝试初始化 BLE 实用程序并更新状态?看起来这个 BleManager 类是被懒惰地调用的,所以它不可能是更高级别的任何东西。

  • 最后它仍然有效,我只是想知道事情的确切顺序实际上是如何在引擎盖下运行以使其正常运行的。

    最佳答案

    他们正在使用信号量来阻止 BleManager 上的任何操作。对象直到中央退出 .unknown状态。
    信号量的初始值为 1。waitinit将其递减为 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/

    相关文章:

    ios - 显示对 Swift 类属性的引用

    ios - 在 [NSRunLoop(NSRunLoop) runMode :beforeDate:] 中发生奇怪的崩溃

    swift - 使用带有 getter 和 setter 的类或结构来计算关系的属性

    ios - Google Map SDK、iOS 和 -ObjC 问题

    ios - 无法识别的选择器发送到实例 - 如何修复 : Error Loading picture from photo album

    python - Locust:我如何仅针对当前 Locust 用户与其余任务共享 auth cookie?

    c++ - 创建线程并让 "this"指针从构造函数中逃逸总是安全的吗?

    c - c中的线程数组创建

    android - Ionic 3 Super Tabs 显示黑屏

    iOS - cocoapods 不更新