Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

<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?

like image 968
Nachum Avatar asked Jan 17 '16 10:01

Nachum


1 Answers

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:

  • Differences between strong and weak in Objective-C
  • Explanation of strong and weak storage in iOS5

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.

like image 128
Toasty Avatar answered Oct 19 '22 22:10

Toasty