CoreBluetooth调用报错求助:未连接调用服务发现及连接引用问题
CoreBluetooth API误用问题分析与解决
这两个问题都是CoreBluetooth开发中新手很容易踩的坑,我帮你逐个拆解:
第一个错误:调用discoverServices时外设未处于连接状态
错误原因
CoreBluetooth有严格的状态规则:只有当外设处于connected状态时,才能调用discoverServices、discoverCharacteristics这类需要和外设交互的方法。你在didDiscover代理方法里直接调用peripheral.discoverServices(),此时外设只是被扫描到,还没和你的设备建立连接,状态是disconnected,完全不符合调用条件,所以触发了API误用警告。
解决方法
正确的流程应该是:扫描到目标外设 → 发起连接 → 连接成功后再发现服务。
修改你的代码如下:
// 先在类里声明一个强引用变量保存外设(后面第二个问题也要用到) var targetPeripheral: CBPeripheral? func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { var peripheralName: String! if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String { peripheralName = name } else { peripheralName = "Unknown" } if let serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID], serviceUUIDs.count == 1 { let targetUUID = serviceUUIDs[0] print(targetUUID) let newPeripheral = Peripheral(id: peripherals.count, name: peripheralName, rssi: RSSI.intValue) if accepted_services.contains(targetUUID.uuidString) { print(newPeripheral) peripherals.append(newPeripheral) // 保存强引用,设置代理,然后发起连接 targetPeripheral = peripheral targetPeripheral?.delegate = self central.connect(targetPeripheral!, options: nil) } } } // 实现连接成功的代理方法,在这里发现服务 func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { print("外设已连接:\(peripheral.name ?? "Unknown")") // 现在可以安全调用discoverServices了 peripheral.discoverServices([CBUUID(string: "4fafc201-1fb5-459e-8fcc-c5c9c331914b")]) }
第二个错误:连接时未持有外设的强引用
错误原因
CBPeripheral对象如果没有被你的代码持有强引用,系统会认为这个外设是“未被使用”的,在连接过程中就会自动取消连接,抛出Cancelling connection for unused peripheral的警告。你之前修改后的代码里,peripheral是didDiscover方法的局部变量,方法执行完毕后这个变量就会被释放,系统找不到对它的强引用,直接终止连接流程。
解决方法
在你的类中声明一个强引用的变量来保存要连接的外设(就像上面代码里的targetPeripheral),确保在连接过程中这个外设对象不会被系统回收。
另外还要补充连接失败和断开的处理,让逻辑更完整:
// 连接失败的代理方法 func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { print("连接失败:\(error?.localizedDescription ?? "未知错误")") targetPeripheral = nil // 清空引用 } // 外设断开连接的代理方法 func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { print("外设已断开连接") targetPeripheral = nil // 清空引用 }
总结一下正确的蓝牙交互流程
- 扫描外设(
centralManager.scanForPeripherals) - 在
didDiscover中匹配目标外设,保存强引用并发起连接 - 在
didConnect中调用discoverServices发现目标服务 - 在
peripheral(_:didDiscoverServices:)中继续发现特征等后续操作
内容的提问来源于stack exchange,提问作者SquareInc
相关产品推荐
相关产品推荐

