Convert Data to Array with modern Swift

Wang Xiaoyu
2 min readMay 9, 2021

Believe it or not, it is incredibly difficult in Swift to read some binary raw data from disk, and interpret them as an array of Float.

The most straightforward method is to create an Array from Data with some initializer like init(from data:Data) . However such initializer doesn’t exist. Without this shortcut, we have to work around it via some middleman.

If we like to do that in C++, obviously that middleman is a pointer referring to the beginning of the chunk of memory owned by Data. In Swift, there is also such pointer, although it is not as easy to use as in C++, which is intended to encourage user to avoid using this Unsafe pointer if possible. There is one, and only one, initializer for Array to be created with typed pointer:
init(unsafeUninitializedCapacity: Int, initializingWith: (inout UnsafeMutableBufferPointer<Element>, inout Int) -> Void)

The usage is not straightforward, which requires a callback function to be implemented. In this function

func convert_to_array<T>(from data:Data) -> [T] {
let capacity = data.count / MemoryLayout<T>.size
let result = [T](unsafeUninitializedCapacity: capaticy) {
pointer, copied_count in
let
length_written = data.copyBytes(to: pointer)
copied_count = length_written / MemoryLayout<T>.size
assert(copied_count == capaticy)
}
return result
}

The conversion from Array to Data is not straightforward as well. The implementation can also be figured out starting from the init()function of proper argument type, which is related to raw memory pointer.

On the other hand, since the raw memory pointer is provide by Array, we can also look for what kind of memory pointer Array can provide, which is acceptable by the constructor of Dat. The pointer turns out to be UnsafeBufferPointer<T> . Therefore the conversion can be implemented around this pointer

func convert_to_data(from array:[T]) -> Data {
var p: UnsafeBufferPointer<T>? = nil
array.withUnsafeBufferPointer { p = $0 }
guard p != nil else
return Data()
}
return Data(buffer: p!)
}

--

--