You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 // 清空引用
}

总结一下正确的蓝牙交互流程

  1. 扫描外设(centralManager.scanForPeripherals)
  2. 在didDiscover中匹配目标外设,保存强引用并发起连接
  3. 在didConnect中调用discoverServices发现目标服务
  4. 在peripheral(_:didDiscoverServices:)中继续发现特征等后续操作

内容的提问来源于stack exchange,提问作者SquareInc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:03:05