I want to send a byte stream using my peripheral class. So I'm asking myself if the queue is needed for thread safety or if it's safe to delete it to unlock the flow.
I have this following struct
private struct WriteWithoutResponseContext {
let data: Data
let characteristic: Characteristic
}
And this two attributes
private var writeWithoutResponseContextQueue = Queue<WriteWithoutResponseContext>()
private let writeWithoutResponseContextCachingDispatchQueue = DispatchQueue(label: "thread-safe-unsent-data-caching", attributes: .concurrent)
I'm using the queue with a barrier to make sure everything is blocked until I added it to the queue when canSendWriteWithoutResponse is false.
How do we know that peripheralIsReady is not happening between check of canSendWriteWithoutResponse and enqueueing of context?
func writeValueWithoutResponse(_ data: Data, for characteristic: Characteristic) {
if self.cbPeripheral.canSendWriteWithoutResponse {
self.cbPeripheral.writeValue(data, for: characteristic, type: .withoutResponse)
} else {
self.writeWithoutResponseContextCachingDispatchQueue.async(flags: .barrier) {
let context = WriteWithoutResponseContext(data: data, characteristic: characteristic)
self.writeWithoutResponseContextQueue.enqueue(context)
}
}
}
func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral) {
self.writeWithoutResponseContextCachingDispatchQueue.sync {
if let unsentContext = self.writeWithoutResponseContextQueue.dequeue() {
self.cbPeripheral.writeValue(unsentContext.data, for: unsentContext.characteristic, type: .withoutResponse)
}
}
}
To be safe you need to specify the Queue your CentralManger
is operating on e.g where your central manager dispatches central role events.
If you not specifying anything the CentralManager will use the main queue which.
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: options)
So in my case just creating the CentralManager with a serial queue is fine.
let serialQueue = DispatchQueue(label: "com.Stackoverflow.64819549", qos: .userInitiated)
self.centralManager = CBCentralManager(delegate: self, queue: serialQueue, options: options)
With that I don't need the barrier anymore.