3

I'm trying to convert a ContiguousArray of Floats into a byte array in Swift but cannot find a smart way without using a for loop. I have been following previous posts such as How to convert a double into a byte array in swift?, but I am unable to retrieve the contents of the array without iteratively getting each element one by one.

Is there an elegant way to directly "copy" the bytes of a ContiguousArray directly to byte array?

PS: I have successfully implemented converting structures into byte arrays, but not able to do the same with arrays.

1
  • 1
    Can you please edit your post and show the desired input an output Commented Nov 21, 2019 at 18:29

1 Answer 1

5

You can use the withUnsafeBytes() method to get a buffer pointer to the underlying bytes of the array's contiguous storage, and directly initialize an [UInt8] array from that buffer pointer. Example:

let floatArray: [Float] = [1.0, 2.0]
// Works also with a ContiguousArray:
// let floatArray: ContiguousArray<Float> = [1.0, 2.0]

let byteArray = floatArray.withUnsafeBytes { Array($0) }
print(byteArray) // [0, 0, 128, 63, 0, 0, 0, 64]

Equivalently (based on Leo's suggestion):

let byteArray = floatArray.withUnsafeBytes(Array.init)

The byte array contains the binary representation of the floating point numbers in host byte order (which is little-endian on all current Apple platforms). A conversion to big-endian is possible, but not without an intermediate copy to an integer array:

let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let intArray = floatArray.map { $0.bitPattern.bigEndian }
let byteArray = intArray.withUnsafeBytes(Array.init)
print(byteArray) // 63, 128, 0, 0, 64, 0, 0, 0]

Reverse conversion: A simple method would be

let floatArray2 = byteArray.withUnsafeBytes { Array($0.bindMemory(to: Float.self)) }
print(floatArray2) // [1.0, 2.0]

However, that requires that the element storage of the byte array is properly aligned for floating point numbers. If that is not guaranteed then you can do

var floatArray2 = [Float](repeating: 0.0, count: byteArray.count / MemoryLayout<Float>.stride)
_ = floatArray2.withUnsafeMutableBytes { byteArray.copyBytes(to: $0) }
print(floatArray2) // [1.0, 2.0]
Sign up to request clarification or add additional context in comments.

5 Comments

or withUnsafeBytes([UInt8].init)
@LeoDabus: Good suggestion! Even withUnsafeBytes(Array.init) works (with automatic type inference).
How would be the opposite direction ?
Super thanks! The Array($0) or Array.init did the trick. Thank you both MartinR @LeoDabus

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.