11

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?

honk
  • 9,137
  • 11
  • 75
  • 83
Nachum
  • 233
  • 1
  • 2
  • 10

1 Answers1

9

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.

Community
  • 1
  • 1
Toasty
  • 116
  • 1
  • 7
  • How do you create a strong reference? – mjk Oct 27 '16 at 18:30
  • This answer is lacking enough detail to really be a good answer. Perhaps there is more information you could provide? – Tibrogargan Oct 27 '16 at 18:56
  • I solved this a long time ago (sorry for not posting an answer). This answer worked for me, I changed centralManager to be a property. – Nachum Oct 30 '16 at 08:20
  • References and memory management are a large topic in and of themselves. I'll try to include some helpful links below. – Toasty Dec 05 '16 at 18:32
  • Sorry, can't edit my comment. I've updated the answer to include more information. Let me know if you'd like additional clarification. – Toasty Dec 05 '16 at 18:56