0

I was followed the code of How to get the status of bluetooth (ON/OFF) in iphone programatically to get the status of bluetooth.

But when I pop the viewController by back navigation button, the app crashed with following error.

[CoreBluetooth] XPC connection invalid

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x170261c80 of class CBCentralManager was deallocated while key value observers were still registered with it. Current observation info: ( Context: 0x1aa9c3710, Property: 0x170056b90> Context: 0x1aa9c3710, Property: 0x170056b00> Context: 0x1aa9c3710, Property: 0x170056b90> Context: 0x1aa9c3710, Property: 0x170056b00> )'

I was tried to remove the observers stated above when calling viewWillDisappear, but error still comes.

[self.bluetoothManager removeObserver:self forKeyPath:@"state"];
[self.bluetoothManager removeObserver:self forKeyPath:@"delegate"];

And I tried

self.bluetoothManager.delegate = nil;

And

self.bluetoothManager = nil;

Sadly all of them no works.

Please give helps.

Update:

I want to show the system pop alert while bluetooth is not turned ON when calling - (void)detectBluetooth. So I add

[self.bluetoothManager init];

in - (void)detectBluetooth.

I found that make the error.

But I can't figure out another method to show the default popup(which with SETTING button).

Community
  • 1
  • 1
KTang
  • 340
  • 1
  • 17

1 Answers1

1

I found the root reason why this error happening.

I did multiple init to the bluetooth manager, so it assign multiple observer itself.

Base on my purpose, to show system alert popup while bluetooth is not turn on. As init will pop the alert, I need to first set nil to bluetooth manager and init in later. That's works with no error.

Here is my final code:

if(!self.bluetoothManager)
{
    // Put on main queue so we can call UIAlertView from delegate callbacks.
    self.bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
} else{
    if (self.bluetoothManager.state != CBManagerStatePoweredOn) {
        self.bluetoothManager = nil;
        self.bluetoothManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
    }
}
[self centralManagerDidUpdateState:self.bluetoothManager];


- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    switch(self.bluetoothManager.state)
    {
        case CBCentralManagerStatePoweredOn: [self pushViewController]; break;
        case CBCentralManagerStateResetting:
        case CBCentralManagerStateUnsupported:
        case CBCentralManagerStateUnauthorized:
        case CBCentralManagerStatePoweredOff:
        default: break;
    }
}
KTang
  • 340
  • 1
  • 17
  • Suggestions: You could use a Singleton object for it (with potentially a delegate/notification) to make your push, or simply use a lazy init: `-(CBCentralManager)bluetoothManager{if(!self.bluuetoothManager){_bluetoothManager = alloc/init/settings, etc.} return _bluetoothManager;}` and in you code, always call your central manager with `self.bluetoothManager` – Larme Dec 22 '16 at 12:37
  • Thank you so much for the advice!! – KTang Dec 29 '16 at 09:54