Time to time, I need to deal with numerical data in swift, and I wrote this Array extension to pack and unpack numbers with data.
extension Array {
var data: Data {
var array = self
let data = Data(buffer: UnsafeBufferPointer<Element>(start: &array, count: self.count))
return data
}
init(data: Data) {
self = data.withUnsafeBytes { [Element]($0.bindMemory(to: Element.self)) }
}
}
It works fine as follows
let values1: [Double] = [1, 2, 3, 5, 7, 11]
let values2 = [Double](data: values1.data)
print(values1) // [1.0, 2.0, 3.0, 5.0, 7.0, 11.0]
print(values2) // [1.0, 2.0, 3.0, 5.0, 7.0, 11.0]
as well as structs
struct Vertex {
var x: Float
var y: Float
var z: Float
var w: Float
var r: UInt8
var g: UInt8
var b: UInt8
var a: UInt8
}
var points1: [Vertex] = [
Vertex(x: 11, y: 12, z: 13, w: 14, r: 15, g: 16, b: 17, a: 18),
Vertex(x: 21, y: 22, z: 23, w: 24, r: 25, g: 26, b: 27, a: 28),
Vertex(x: 31, y: 32, z: 33, w: 34, r: 35, g: 36, b: 37, a: 38),
]
let data2 = points1.data
let points2 = [Vertex](data: data2)
print(points1) // [__lldb_expr_17.Vertex(x: 11.0, y: 12.0, z: 13.0, w: 14.0, r: 15, g: 16, b: 17, a: 18), __lldb_expr_17.Vertex(x: 21.0, y: 22.0, z: 23.0, w: 24.0, r: 25, g: 26, b: 27, a: 28), __lldb_expr_17.Vertex(x: 31.0, y: 32.0, z: 33.0, w: 34.0, r: 35, g: 36, b: 37, a: 38)]
print(points2) // [__lldb_expr_17.Vertex(x: 11.0, y: 12.0, z: 13.0, w: 14.0, r: 15, g: 16, b: 17, a: 18), __lldb_expr_17.Vertex(x: 21.0, y: 22.0, z: 23.0, w: 24.0, r: 25, g: 26, b: 27, a: 28), __lldb_expr_17.Vertex(x: 31.0, y: 32.0, z: 33.0, w: 34.0, r: 35, g: 36, b: 37, a: 38)]
Then I have three questions.
How to fix warnings around
UnsafeBufferPointer
.Initialization of 'UnsafeBufferPointer' results in a dangling buffer pointer
I like to prevent none struct type, such as classes to use this extension. Is there any way to do this like using 'where Element is struct' (of cause error).
Why following code works? String isn't a fixed length data, is it?
let strings1: [String] = ["Tokyo", "New York", "London"]
print(strings1) // ["Tokyo", "New York", "London"]
let data3 = strings1.data
let strings3 = [String](data: data3)
print(strings3) // ["Tokyo", "New York", "London"]