9

So there's a way to monitor state changes of CBCentralManager via centralManagerDidUpdateState(). But is there a similar method call to monitor state changes for CBPeripheral? I couldn't find anything exposed in CoreBluetooth library, and I want to call a function whenever CBPeripheralState changes.

Right now all I have is a switch statement which checks the peripheral state, but it'll always just return either connected or disconnected. How would I get to the connecting/disconnecting cases? I've tried placing my switch statement in various parts of my code, from the bleInit() method, to startScanning(), connectToPeripheral(), etc

switch(peripheral.state){
case .disconnected:
    print("disconnected")
case .connecting:
    print("connecting")
case .connected:
    print("connected")
case .disconnecting:
    print("disconnecting")
default: break
}
casillas
  • 16,351
  • 19
  • 115
  • 215
Alfred Ly
  • 123
  • 1
  • 8

3 Answers3

6

The connecting and disconnecting states are transitionary states. Your connection will only be in those states for a very brief time; which is why you will never see those states.

If your app is acting as a central then peripheral connection state is notified via the CBCentralManager's didConnect and didDisconnectPeripheral methods.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • I'm able to get didConnect and didDisconnect up and running and the peripheral states are being displayed as expected. However to recap, I won't be able to get notified of connecting and disconnecting states because they happen so quickly? Out of curiosity, why are those cases exposed in the API? What usage would they normally serve? – Alfred Ly Apr 05 '17 at 20:37
  • I imagine Apple uses them within the CoreBluetooth state tracking internally. I probably shouldn't say you will "never" see them, it is just extremely unlikely that you would happen to read the status variable at the instant that the peripheral is in one of those states. – Paulw11 Apr 05 '17 at 20:41
  • This might be deviating off topic, but is there any way to check for the cause of reason for a Peripheral disconnect (not considering factors like distance or signal strength), whether it's on my app side or the hardware side that dropped the connection? I believe I read somewhere that Apple doesn't time out connections as long as the app is in the foreground. – Alfred Ly Apr 05 '17 at 20:50
  • Not as far as I know. If your app initiates the disconnect, you know that is the reason because you did it. If the peripheral disconnects and your app didn't initiate the disconnect then it is because the peripheral "went away"; this could be because it was powered off, went out of range or simply terminated the connection – Paulw11 Apr 05 '17 at 20:56
  • This doesn't fire every time. If you disable bluetooth on your phone just before sending the message, this delegate will never trigger, but CBPeripheral will be in disconnected state. You will receive centralManagerDidUpdateState call, but not didDisconnectPeripheral. – Raimundas Sakalauskas Sep 11 '18 at 12:04
  • The connecting state is very useful. If your device is out of range, you can sit in the connecting state for basically forever, until the device advertises and the phone connects. – sidekickr Jan 17 '20 at 02:00
3

CBPeripheral's state property is KVO-compliant, hence you can easily add an object as observer and monitor all state transitions.

Note though that for some reason some state transitions are strange, i.e. when a peripheral moves from disconnected to disconnecting without any intermediate states. I'm afraid that's bugs in the CoreBluetooth stack.

DrMickeyLauer
  • 4,455
  • 3
  • 31
  • 67
-2

I think peripheralManagerDidUpdateState (https://developer.apple.com/reference/corebluetooth/cbperipheralmanagerdelegate/1393271-peripheralmanagerdidupdatestate) does what you want?

Femi
  • 64,273
  • 8
  • 118
  • 148
  • That's what I thought too, but from my understanding, contrary to the expected naming convention, CBCentralManager manages CBPeripherals, and CBPeripheralManager manages CBCentral. CBCentralManager manages discovered/connected peripherals, and CBPeripheral is an instance object that represents a peripheral device. CBPeripheralManager manages the published services within the peripheral to advertise, while CBCentral is an instance object representing the central device connected to the peripheral – Alfred Ly Apr 05 '17 at 19:37
  • No, that's for the state of the CBCentralManager. – I make my mark Jul 24 '20 at 15:00