This seems to be a common issue for beginners in swift. I read many of the cases but I have not found any explanation that addresses my case.
I am using IOBluetooth to open a bluetooth serial connection.
I need to use UnsafeMutablePointer<BluetoothRFCOMMChannelId>
I set it up like this
var rfcommChannel: IOBluetoothRFCOMMChannel? = nil
var rfcommChannelID: BluetoothRFCOMMChannelID? = nil
let channelIdResult = service?.getRFCOMMChannelID(&rfcommChannelID)
if channelIdResult != kIOReturnSuccess {
print("Failed to get RFCOMM channel ID: \(String(describing: channelIdResult))")
return
}
print(rfcommChannelID as Any) // Optional(2)
_ = device?.openRFCOMMChannelAsync(&rfcommChannel, withChannelID: rfcommChannelID!, delegate: self)
the application crashes with
Fatal error: Unexpectedly found nil while unwrapping an Optional value
I have tried
if let rfcommChannelID = rfcommChannelID {
_ = device?.openRFCOMMChannelAsync(&rfcommChannel, withChannelID: rfcommChannelID, delegate: self)
} else {
print("failed for some reason")
}
which always fails for some reason. What am I missing? it works if I hard code the id's but that does't really help
I can see that the value is NOT nil in the debugger, yet every test use considers the value nil. Even printing to the console prints optional(2) which is the correct value
This code is not correct:
getRFCOMMChannelID()
takes a pointer to aBluetoothRFCOMMChannelID
, not a pointer to aBluetoothRFCOMMChannelID?
. This type is really just a typealias forUInt8
. AUInt8
is not the same size as aUInt8?
(the first is 1 bytes; the second is 2 byte). So getRFCOMMChannelID updates the first byte of a two byte value, and corrupts the data structure.What you mean is this:
It's correct for
rfcommChannel
to be Optional, since that's whatopenRFCOMMChannelAsync
accepts.Why doesn't the compiler catch this mistake? Honestly, I'm not completely certain. This may be a compiler bug. I'm still pondering if there are situations where it is particularly convenient that this is allowed for compatibility with existing C code. (IOBluetooth has not been nullability-audited for Swift. I'm not sure that matters, but it might be related to the bug.)