简体   繁体   中英

How to convert different type values to data byte

I am writing an application where I need to convert an array of different data types to a data array which I will send to another device through a UDP port.

So far, I have the following code:

class ViewController: NSViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    let a: UInt8 = 42

    var da:[UInt8] = [a]
    let data = Data(buffer: UnsafeBufferPointer(start: &da, count: da.count))
    let x = data.toArray(type: UInt8.self)
    print(x)
  }
}

So far, this works. I get the following output: [42]
If I were to change let a: UInt8 = 42 to let a: Float = 3.14 and var da:[Float] = [a] , I get the result of [195, 245, 72, 64] .

All of the above is what I expect. The problem comes in the following code:

class ViewController: NSViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    let b: UInt8 = 42
    let a: Float = 3.14

    var da:[Any] = [a, b]
    let data = Data(buffer: UnsafeBufferPointer(start: &da, count: da.count))
    let x = data.toArray(type: UInt8.self)
    print(x)
  }
}

Here, I would expect to get [42, 195, 245, 72, 64] except I am getting the following result: [42, 0, 0, 0, 0, 0, 0, 0, 176, 10, 10, 0, 0, 96, 0, 0, 104, 41, 172, 143, 255, 127, 0, 0, 32, 161, 114, 0, 1, 0, 0, 0, 195, 245, 72, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 228, 32, 1, 1, 0, 0, 0, 168, 153, 114, 0, 1, 0, 0, 0] .

Can someone explain to my why this is happening and what I should change to get the expected outcome?

Edit: While I could skip the padding, I am trying to fake a server that is from the below specification while I am developing the app.
https://forums.codemasters.com/discussion/136948/f1-2018-udp-specification#latest

You are seeing the internal memory representation of Any .

print(MemoryLayout<Any>.size) //-> 32

The value of type Any is represented in a hidden struct of size 32, which may contain a raw value of some primitive data or an address of reference type instance or huge struct, as well as some meta data about the type of the contained value.

It's not a simple padding.


You can write something like this:

(You may need to control padding yourself, if needed.)

protocol ByteRepresentable {
    var bytes: Data {get}
}
extension ByteRepresentable {
    var bytes: Data {
        var copiedSelf = self
        return Data(bytes: &copiedSelf, count: MemoryLayout.size(ofValue: self))
    }
}
extension UInt8: ByteRepresentable {}
extension Float: ByteRepresentable {}
//...

let a: UInt8 = 42
let b: Float = 3.14

let da: [ByteRepresentable] = [a, b]
var data = da.reduce(into: Data(), {$0.append($1.bytes)})
print(Array(data)) //->[42, 195, 245, 72, 64]

If you want to write an extension:

extension Array where Element == ByteRepresentable {
    func toData() -> Data {
        return self.reduce(into: Data(), {$0.append($1.bytes)})
    }
}

print(Array(da.toData())) //->[42, 195, 245, 72, 64]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM