I know how to do it in java (see here), but I couldn\'t find a swift equivalent for java\'s ByteBuffer, and consequently its .putDouble(double value) method.
Basically,func byteArray<T>(_ value: T) -> [UInt8] {
var value = value
var initialArray = withUnsafeBytes(of: &value) { Array($0) }
initialArray.reverse()
var count = initialArray.count
while initialArray.first == 0 && count > 1 {
initialArray[0...count - 2] = initialArray[1...count - 1]
count -= 1
}
if initialArray[0] >= 128 {
var newArray = [UInt8](repeating: 0, count: count + 1)
newArray[0] = UInt8(0)
newArray[1...count] = initialArray[0...count - 1]
return newArray
} else {
return Array(initialArray[0...count - 1])
}
}
Well, it wasn't easy, but here it is:
func doubleToByteArray(value: Double) -> [UInt8] {
let count = sizeof(Double)
var doubles: [Double] = [value]
let data = NSData(bytes: doubles, length: count)
var result = [UInt8](count: count, repeatedValue: 0)
data.getBytes(&result, length: count)
return result
}
Use with caution.
The accepted answers are dangerous because of the fact that the MemoryLayout provides you the size of the static type T!
To workaround the problem you should create a custom protocol and ask for Self in it:
protocol ByteConvertible {}
extension ByteConvertible {
func toBytes() -> [UInt8] {
let capacity = MemoryLayout<Self>.size
var mutableValue = self
return withUnsafePointer(to: &mutableValue) {
return $0.withMemoryRebound(to: UInt8.self, capacity: capacity) {
return Array(UnsafeBufferPointer(start: $0, count: capacity))
}
}
}
}
I mentioned before that the accepted answers are dangerous and here is an example why:
let num = UInt8(42)
MemoryLayout.size(ofValue: num) //=> 1 byte as expected
let any: Any = num
MemoryLayout.size(ofValue: any) //=> 32 bytes which is what will happen in the generic functions from the all the answers
Swift 3.0
Here's my updated version to the original solution.
/// input: array of bytes
/// -> get pointer to byte array (UnsafeBufferPointer<[Byte]>)
/// -> access its base address
/// -> rebind memory to target type T (UnsafeMutablePointer<T>)
/// -> extract and return the value of target type
func binarytotype <T> (_ value: [Byte], _: T.Type) -> T
{
return value.withUnsafeBufferPointer {
$0.baseAddress!
.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
/// input type: value of type T
/// -> get pointer to value of T
/// -> rebind memory to the target type, which is a byte array
/// -> create array with a buffer pointer initialized with the source pointer
/// -> return the resulted array
func typetobinary <T> (_ value: T) -> [Byte]
{
var mv : T = value
let s : Int = MemoryLayout<T>.size
return withUnsafePointer(to: &mv) {
$0.withMemoryRebound(to: Byte.self, capacity: s) {
Array(UnsafeBufferPointer(start: $0, count: s))
}
}
}
PS: Don't forget to replace Byte with UInt8.
typealias Byte = UInt8
func toByteArray<T>(var value: T) -> [Byte] {
return withUnsafePointer(&value) {
Array(UnsafeBufferPointer(start: UnsafePointer<Byte>($0), count: sizeof(T)))
}
}
toByteArray(1729.1729)
toByteArray(1729.1729 as Float)
toByteArray(1729)
toByteArray(-1729)
But the results are reversed from your expectations (because of endianness):
[234, 149, 178, 12, 177, 4, 155, 64]
[136, 37, 216, 68]
[193, 6, 0, 0, 0, 0, 0, 0]
[63, 249, 255, 255, 255, 255, 255, 255]
Added:
func fromByteArray<T>(value: [Byte], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}
let a: Double = 1729.1729
let b = toByteArray(a) // -> [234, 149, 178, 12, 177, 4, 155, 64]
let c = fromByteArray(b, Double.self) // -> 1729.1729
For Xcode8/Swift3.0:
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
}
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
For Xcode8.1/Swift3.0.1
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafeBytes(of: &value) { Array($0) }
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBytes {
$0.baseAddress!.load(as: T.self)
}
}
Solution in swift 3:
public func toByteArray<T>(_ value: T) -> [Byte] {
let totalBytes = MemoryLayout<T>.size
var value = value
return withUnsafePointer(to: &value) { valuePtr in
return valuePtr.withMemoryRebound(to: Byte.self, capacity: totalBytes) { reboundPtr in
return Array(UnsafeBufferPointer(start: reboundPtr, count: totalBytes))
}
}
}