Search code examples
iosobjective-ccore-bluetooth

<Error>: [CoreBluetooth] API MISUSE: Cancelling connection for unused peripheral


My scenario:

  1. I kill my app with sigkill() -> app goes to background.
  2. Data is sent from BT device and it connects successfully while invoking centralManager: willRestoreState: as it should.
  3. After the device is connected I take the BT device out of the apps range and the method centralManager: didDisconnectPeripheral: error: is invoked with error code 6.
  4. I try to reconnect the peripheral by calling [_centralManager connectPeripheral:peripheral options:nil] and then I get the following error:

[CoreBluetooth] API MISUSE: Cancelling connection for unused peripheral , Did you forget to keep a reference to it?

What does this error mean?


Solution

  • As the message suggests, you need to store your CBPeripheral instance somewhere that keeps a strong reference to it.

    In general, you have a strong reference to an object by storing the pointer somewhere. For example, you might have a BluetoothConnectionManager keeps a list of connected peripherals:

    @implementation BluetoothConnectionManager
    - (instancetype)init
    {
        if(self = [super init])
        {
            _knownPeripherals = [NSMutableArray array];
            dispatch_queue_t centralQueue = dispatch_queue_create("com.my.company.app", DISPATCH_QUEUE_SERIAL);
            _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:@{CBCentralManagerOptionShowPowerAlertKey : @YES}];
        }
        return self;
    }
    
    - (void)centralManager:(CBCentralManager *)central
      didConnectPeripheral:(CBPeripheral *)peripheral
    {
        [_knownPeripherals addObject:peripheral];
    }
    
    - (void)centralManager:(CBCentralManager *)central
    didDisconnectPeripheral:(CBPeripheral *)cbPeripheral
                     error:(NSError *)error
    {
        // This probably shouldn't happen, as you'll get the 'didConnectPeripheral' callback
        // on any connected peripherals and add it there.
        if(![_knownPeripherals containsObject:cbPeripheral])
        {
            [_knownPeripherals addObject:cbPeripheral];
        }
    
        [_centralManager connectPeripheral:cbPeripheral options:nil];
    }
    
    @end
    

    Or you can modify this code to have a reference to a single, connected peripheral.

    You can also use this to write out your previous connection ids to try and establish them when re-launching the app as described in the Apple Docs

    Finally, a few links on references:

    Doing a search on "strong and weak references ios" will yield additional results. If you're using ARC, simply having a property will create a strong reference. Regardless, adding the CBPeripheral instance to an array will also create a strong reference.