Last time I talked about turning a Data
object into a single scalar. Now I’m going to turn a Data
object into an array of scalars.
Based on the last post, it’s tempting to try something like this:
let data = Data(bytes: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]) let array = data.withUnsafeBytes { (pointer: UnsafePointer<[Int8]>) -> [Int8] in return pointer.pointee // EXC_BAD_ACCESS }
For that to work, the sequence of bytes that start at pointer
must match the in memory representation of a Swift array containing those eight Int8
values. C arrays work like that. Swift arrays don’t. Swift arrays are more complex than a sequence of bytes. If you tried the code above, you’d get a runtime crash.
Swift uses UnsafeBufferPointer
to point to some sequence of bytes in memory. You can create an UnsafeBufferPointer
from an UnsafePointer
. And Array
has an initializer that takes such a buffer pointer. Here’s how to turn that data into an array of Int8
values.
So the plan is:
- Access an
UnsafePointer
with the methodwithUnsafeBytes
- Use the
UnsafePointer
to create anUnsafeBufferPointer
- Use the
UnsafeBufferPointer
to create anArray
.
The type of the Array
elements will be the type of the UnsafePointer
in the closure given to withUnsafeBytes
. Here’s one way to do this to create an [Int8]
.
let data = Data(bytes: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]) let array = data.withUnsafeBytes { (pointer: UnsafePointer<Int8>) -> [Int8] in let buffer = UnsafeBufferPointer(start: pointer, count: data.count) return Array<Int8>(buffer) } // array == [1, 0, 0, 0, 2, 0, 0, 0]
The code above interprets the data as 8 1-byte values. It’s just as valid to interpret that data as 2 4-byte values, like below.
let data = Data(bytes: [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]) let array = data.withUnsafeBytes { (pointer: UnsafePointer<Int32>) -> [Int32] in let buffer = UnsafeBufferPointer(start: pointer, count: data.count / 4) return Array<Int32>(buffer) } // array == [1, 2]
As with decoding numbers, ff you received data from a Bluetooth device with CoreBluetooth
, there is no information to tell you how to decode the object. There’s also no guarantee the order of the bytes will match the expected values in the Int32
example above. It’s necessary to know ahead of time what the Data
object represents.