我正在尝试使用该方法来简单地读Data入Swift 4 。问题struct``withUnsafeBytes
Data
struct``withUnsafeBytes
网络UDP数据包具有以下格式:
data: 0102 0A00 0000 0B00 0000 01 : 1 byte : majorVersion (decimal 01) 02 : 1 byte : minorVersion (decimal 02) 0A00 0000 : 4 bytes: applicationHostId (decimal 10) 0B00 0000 : 4 bytes: versionNumber (decimal 11)
然后我有一个扩展名Data,需要一个start和length个要读取的字节
start
length
extension Data { func scanValue<T>(start: Int, length: Int) -> T { return self.subdata(in: start..<start+length).withUnsafeBytes { $0.pointee } } }
当一一读取值时,这可以正常工作:
// correctly read as decimal "1" let majorVersion: UInt8 = data.scanValue(start: 0, length: 1) // correctly read as decimal "2" let minorVersion: UInt8 = data.scanValue(start: 1, length: 1) // correctly read as decimal "10" let applicationHostId: UInt32 = data.scanValue(start: 2, length: 4) // correctly read as decimal "11" let versionNumber: UInt32 = data.scanValue(start: 6, length: 4)
然后我创建了一个struct代表整个数据包的,如下所示
struct
struct XPLBeacon { var majorVersion: UInt8 // 1 Byte var minorVersion: UInt8 // 1 Byte var applicationHostId: UInt32 // 4 Bytes var versionNumber: UInt32 // 4 Bytes }
但是,当我直接将数据读入结构时,我遇到了一些问题:
var beacon: XPLBeacon = data.scanValue(start: 0, length: data.count) // correctly read as decimal "1" beacon.majorVersion // correctly read as decimal "2" beacon.minorVersion // not correctly read beacon.applicationHostId // not correctly read beacon.versionNumber
我应该像这样解析整个结构吗?
从数据读取整个结构不起作用,因为struct成员被 填充 到其自然边界。的内存布局struct XPLBeacon是
struct XPLBeacon
AB xx CCCCDDDD
哪里
抵消成员 0 A-majorVersion(UInt8) 1 B-minorVersion(UInt8) 2 xx-填充 4 CCCC-applicationHostId(UInt32) 8 DDDD-版本号(UInt32)
并插入填充,以便将UInt32成员对齐到其大小倍数的内存地址。这也得到了证实
UInt32
print(MemoryLayout<XPLBeacon>.size) // 12
(有关Swift中对齐的更多信息,请参见 Type Layout)。
如果将整个数据读入结构,则按以下方式分配字节
01 02 0A 00 00 00 0B 00 00 00 AB xx CCCCDDDD
这就解释了为什么major/minorVersion是正确的,但applicationHostId并 versionNumber 是错误的。从数据中单独读取所有成员是正确的解决方案。
major/minorVersion
applicationHostId
versionNumber