1

Question

How do I use the latest (swift 5) Data API to convert a Data() object into an Array of structs?

Example

Prior to Swift 5 I had this code to convert a Data() object into a [Point] array

import Foundation

struct Point {
    let x: Float
    let y: Float
}

let pt1 = Point(x: 1, y: 1)
let pt2 = Point(x: 2, y: 2)

let points: [Point] = [pt1, pt2]

let pointData = Data(
    bytes: points,
    count: MemoryLayout<Point>.size * points.count
)

print(pointData.count)


var newPoints = [Point]()

// ** Deprecated **
pointData.withUnsafeBytes { (bytes: UnsafePointer<Point>) in
    newPoints = Array(UnsafeBufferPointer(start: bytes, count: pointData.count / MemoryLayout<Point>.size))
}

print(newPoints.count) // 2
print(newPoints[0])    // Point(x: 1.0, y: 1.0)
print(newPoints[1])    // Point(x: 2.0, y: 2.0)

The withUnsafeBytes is now deprecated:

withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead

But I don't know how to use the new Data API to convert my pointData into a [Point] array.


Here's a similar answer that works on a single object, but I'm struggling to apply it to my array example.

tospig
  • 7,762
  • 14
  • 40
  • 79
  • 1
    Possibly helpful: [round trip Swift number types to/from Data](https://stackoverflow.com/questions/38023838/round-trip-swift-number-types-to-from-data). – Martin R Jul 27 '21 at 11:25

1 Answers1

2

You should now use the new withUnsafeBytes that takes a closure that takes a UnsafeRawBufferPointer as argument. You now don't need to do all the MemoryLayout calculations by hand, and can just bind the memory directly to the desired type.

pointData.withUnsafeBytes { rawBufferPointer in
    newPoints = Array(rawBufferPointer.bindMemory(to: Point.self))
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313