Home > front end >  Undocumented API changes in CoreBluetooth
Undocumented API changes in CoreBluetooth

Time:12-02

In Xcode 12.3, CoreBluetooth.CBService.peripheral is defined in objective-c as:

@property(assign, readonly, nonatomic) CBPeripheral *peripheral;

Update: Here's the swift translation of the above in Xcode 12.3:

unowned(unsafe) open var peripheral: CBPeripheral { get }

In Xcode 13.0, CBService.peripheral is defined in swift as:

weak var peripheral: CBPeripheral? { get }

Apple's documentation states that this API has existing since iOS5 and there have been no changes. However in Xcode 13, the variable is clearly an optional. (And it is not an optional in Xcode 12.3 as it is missing the attribute nullable.)

The fix is relatively easy (e.g. service.peripheral -> service?.peripheral) - but it makes it impossible to use the same code for both Xcode 12.3 and 13.0. I'm wondering if there is some nuance here that that I'm missing?

CodePudding user response:

Optionals are an inherent part of Swift and they are not part of Objective-C. A non-null reference in Swift in guaranteed to have a value while any reference in Objective C could, in theory, be null.

The nullable and nonnull decorators were introduced to improve interoperability with Swift with the side effect that they also more clearly document Objective C APIs.

Core Bluetooth is an Objective C API and, as you note, it has been available since iOS5; Well before Swift and the nullable decorator.

So, it isn't so much that the API has changed, but rather you are comparing the Objective C API with the Swift API and Apple has not added the nullable decorator to the Core Bluetooth API.

Neither of these APIs have changed; The Swift declaration for peripheral on CBService has always been an optional. The Objective-C declaration has never had nullable but a null value has always been possible.

Adding nullable wouldn't change the behaviour of the API, just its declaration in Objective C. This would potentially be a breaking change for Objective-C code, or at least could cause compilation to fail, so there is no reason for Apple to change it and a good reason not to.

Update

From your comment, there does, indeed, appear to have been a breaking change in the Swift declaration of CBService.peripheral from unowned(unsafe) to a weak optional.

This is a much safer declaration, since in the previous definition the onus was on you to check that peripheral wasn't nil and there was a potential crash if you didn't.

In my many years of programming with Core Bluetooth, I don't think I have ever needed to use CBService.peripheral, however, you can use conditional compilation based on the Swift version to write code that works in both Xcode 13 and earlier versions:

var p: CBPeripheral?
#if swift(<5.5) 
    if s.peripheral != nil {
        p = s.peripheral
    }
#else
        p = s.peripheral
#endif
  • Related