CoreBluetooth调用discoverServices报错及连接异常问题求助
Hey there, let's work through these two CoreBluetooth API misuse issues you're hitting—they're common pitfalls, but easy to fix once you know the root causes!
1. First Error: discoverServices called on a disconnected peripheral
What's causing it?
When the didDiscover delegate method fires, the CBPeripheral object it gives you is only discovered via BLE advertising—it's not connected to your device yet. CoreBluetooth strictly requires peripherals to be in the connected state before you can call methods like discoverServices. Your original code skips the connection step entirely, which triggers the API misuse warning.
How to fix it
You need to follow CoreBluetooth's standard workflow:
- First, initiate a connection to the discovered peripheral
- Wait for the connection to be confirmed via the
didConnectdelegate method - Only then call
discoverServices
2. Second Error: Cancelling connection for unused peripheral
What's causing it?
In your second code snippet, the CBPeripheral instance is a local variable inside the didDiscover method. As soon as that method finishes executing, ARC (Automatic Reference Counting) deallocates the peripheral because there's no strong reference keeping it alive. CoreBluetooth detects this and cancels the connection, since the peripheral is no longer "active" in your app.
How to fix it
Store a class-level strong reference to the peripheral (e.g., a property in your Bluetooth manager class). This keeps the object alive while the connection process and subsequent BLE operations are running.
Full Fixed Code Example
Here's a complete, corrected implementation that addresses both issues:
class BluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { // CoreBluetooth objects private var centralManager: CBCentralManager! private var connectedPeripheral: CBPeripheral? // Strong reference to keep peripheral alive // Your custom properties private var peripherals: [Peripheral] = [] private let targetServiceUUID = CBUUID(string: "4fafc201-1fb5-459e-8fcc-c5c9c331914b") private let acceptedServices = ["4fafc201-1fb5-459e-8fcc-c5c9c331914b"] override init() { super.init() centralManager = CBCentralManager(delegate: self, queue: nil) } // MARK: - CBCentralManagerDelegate func centralManagerDidUpdateState(_ central: CBCentralManager) { if central.state == .poweredOn { // Start scanning for peripherals advertising our target service central.scanForPeripherals(withServices: [targetServiceUUID], options: nil) } } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? String ?? "Unknown" // Verify the peripheral advertises our accepted service guard let serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID], serviceUUIDs.contains(where: { acceptedServices.contains($0.uuidString) }) else { return } let newPeripheral = Peripheral(id: peripherals.count, name: peripheralName, rssi: RSSI.intValue) print("Discovered valid peripheral: \(newPeripheral)") // Stop scanning to avoid duplicate discoveries central.stopScan() // Store strong reference and set delegate before connecting connectedPeripheral = peripheral peripheral.delegate = self // Initiate connection central.connect(peripheral, options: nil) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { print("Successfully connected to \(peripheral.name ?? "Unknown")") // Now we can safely discover services peripheral.discoverServices([targetServiceUUID]) } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { print("Connection failed: \(error?.localizedDescription ?? "Unknown error")") connectedPeripheral = nil // Clear reference on failure // Restart scanning if needed central.scanForPeripherals(withServices: [targetServiceUUID], options: nil) } // MARK: - CBPeripheralDelegate func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { if let error = error { print("Service discovery failed: \(error.localizedDescription)") return } guard let services = peripheral.services else { return } for service in services { print("Discovered service: \(service.uuid)") // Optional: Discover characteristics for the service peripheral.discoverCharacteristics(nil, for: service) } } } // Your custom Peripheral model struct Peripheral { let id: Int let name: String let rssi: Int }
Key Takeaways
- Always follow CoreBluetooth's sequence: Scan → Discover → Connect → Discover Services → Discover Characteristics
- Never call service/characteristic discovery methods on a disconnected peripheral
- Maintain a strong reference to any
CBPeripheralyou're interacting with to prevent ARC from deallocating it prematurely
内容的提问来源于stack exchange,提问作者SquareInc

