I have a swift structure which contains a number of items:
struct ConfigParams {
var MessageID: UInt16 = 0
var SN: UInt16 = 1
var ManufactureData: UInt32 = 0
var Version = [Character](repeating:"?", count:16)
}
And a member function that returns this as a Data type for transmission over the netork:
func asData() -> Data {
var data = Data()
data.append(withUnsafeBytes(of: MessageID) { Data($0)})
data.append(withUnsafeBytes(of: SN) { Data($0)})
data.append(withUnsafeBytes(of: ManufactureData) { Data($0)})
print("My size before \(data.count)")
data.append(withUnsafeBytes(of: Version) { Data($0)})
print("My size after \(data.count)")
print(Version.count)
return data
}
When I call "asData()" it gives a Data() with the wrong count of bytes in it! The output of calling the above method is:
My size before 8
My size after 16
16
So when I append the contents of Version it it only adding 8 bytes, not 16. But I would expect the final size to be 24! What am I missing here?
There are actually two things wrong here.
-
The global
withUnsafeBytes(of:)
function is only useful when the raw bytes are stored as the direct value itself, such as with "trivial" types likeUInt16
. An array isn't a trivial type because it doesn't store its data inline in that way. -
The
Character
type isn't a trivial type either. It has no pre-determined representation in a known number of bits.
Since your Version
seems to be intended to be an array of C-style characters (i.e. as 8-bit bytes), you'd probably be better off modeling it like this:
var Version = [UInt8](repeating:0x3F, count:16)
Now, since that array has a trivial element type, you can use Array
's withUnsafeBytes(_:)
method to get scoped access to a contiguous buffer of the 16 raw bytes:
Version.withUnsafeBufferPointer { bytes in
data.append(contentsOf: bytes)
}
Of course, this has other code consequences, because it changes the element type of the Version
array.