I got this code here from an app I am working on. I inherited this code when the BLE guy left the team. I am not good with low level stuff and Data stuff. I am UI/UX front end person, and now I do need to get my hands dirty. This code is now a bit old and using deprecated code. I have unsuccessfully been trying to silence the warning, but I keep ending up with he same code or with errors.
This is the code that generates the warning. On the return line when using withUnsafeBytes
extension Data {
func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
let length = MemoryLayout<T>.size
guard self.count >= start + length else {
return (invalid, start+length)
}
return (self.subdata(in: start..<start+length).withUnsafeBytes{ $0.pointee }, start+length)
}
}
This method is used to decode a byte array to a struct. I get the data from a BLE service and the various vars are packed into an array of bytes.
If any one as a fix for this or a better way to do id.
The version of withUnsafeBytes
that's deprecated here is the version which binds the underlying pointer to a known type (Data.withUnsafeBytes<R, T>(_ body: (UnsafePointer<T>) throws -> R) rethrows -> R
).
The preferred replacement is the version which does not bind in this way, and returns a raw buffer pointer (withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
); luckily, transitioning between these only changes how you read from the pointer:
extension Data {
func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
let length = MemoryLayout<T>.size
guard self.count >= start + length else {
return (invalid, start + length)
}
return (self.subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) }, start + length)
}
}
Using UnsafeRawBufferPointer.load(as:)
you can safely read a trivial type T
from the buffer. (Note that this method is not safe to call for non-trivial types, but this was true of the original version of the method too.)
If you want to simplify even a bit further, you can avoid repeating start + length
:
func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
let length = MemoryLayout<T>.size
var value = invalid
if count >= start + length {
value = subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) }
}
return (value, start + length)
}
or even shorter, at the cost of readability:
func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
let length = MemoryLayout<T>.size
let value = count >= start + length ? subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) } : invalid
return (value, start + length)
}