How to convert a double into a byte array in swift?

前端 未结 7 1161
南笙
南笙 2020-11-27 17:02

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,
相关标签:
7条回答
  • 2020-11-27 17:12
    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])
        }
    }
    
    0 讨论(0)
  • 2020-11-27 17:13

    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.

    0 讨论(0)
  • 2020-11-27 17:16

    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

    0 讨论(0)
  • 2020-11-27 17:18

    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.

    0 讨论(0)
  • 2020-11-27 17:25
    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)
        }
    }
    
    0 讨论(0)
  • 2020-11-27 17:32

    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))
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题