我正在尝试使用该方法将其读Data入Swift 4 .问题structwithUnsafeBytes
网络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)
Run Code Online (Sandbox Code Playgroud)
然后我有一个扩展Data,需要一个start和length几个字节来读取
extension Data {
func scanValue<T>(start: Int, length: Int) -> T {
return self.subdata(in: start..<start+length).withUnsafeBytes { $0.pointee }
}
}
Run Code Online (Sandbox Code Playgroud)
这在逐个读取值时正常工作:
// 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)
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个struct代表整个数据包的如下
struct XPLBeacon {
var majorVersion: UInt8 // 1 Byte
var minorVersion: UInt8 // 1 Byte
var applicationHostId: UInt32 // 4 Bytes
var versionNumber: UInt32 // 4 Bytes
}
Run Code Online (Sandbox Code Playgroud)
但是当我直接将数据读入结构时,我遇到了一些问题:
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
Run Code Online (Sandbox Code Playgroud)
我应该工作解析这样的整个结构?
从数据中读取整个结构不起作用,因为结构成员被填充到它们的自然边界。的内存布局struct XPLBeacon是
AB xx CCCCDDDD
在哪里
抵消成员 0 A - 主要版本 (UInt8) 1 B - 次要版本 (UInt8) 2 xx - 填充 4 CCCC - applicationHostId (UInt32) 8 DDDD - 版本号 (UInt32)
并插入填充,以便UInt32成员与内存地址对齐,内存地址是其大小的倍数。这也得到了证实
print(MemoryLayout<XPLBeacon>.size) // 12
Run Code Online (Sandbox Code Playgroud)
(有关 Swift 中对齐的更多信息,请参阅 类型布局)。
如果将整个数据读入结构体,则字节分配如下
01 02 0A 00 00 00 0B 00 00 00 AB xx CCCCDDDD
这就解释了为什么major/minorVersion是正确的,但applicationHostId并 versionNumber
是错误的。从数据中单独读取所有成员是正确的解决方案。
由于雨燕3数据符合RandomAccessCollection,MutableCollection,RangeReplaceableCollection.因此,您只需创建一个自定义初始值设定项来初始化您的struct属性,如下所示:
struct XPLBeacon {
let majorVersion, minorVersion: UInt8 // 1 + 1 = 2 Bytes
let applicationHostId, versionNumber: UInt32 // 4 + 4 = 8 Bytes
init(data: Data) {
self.majorVersion = data[0...0].withUnsafeBytes { $0.pointee }
self.minorVersion = data[1...1].withUnsafeBytes { $0.pointee }
self.applicationHostId = data[2...5].withUnsafeBytes { $0.pointee }
self.versionNumber = data[6...9].withUnsafeBytes { $0.pointee }
}
}
Run Code Online (Sandbox Code Playgroud)
let data = Data([0x01,0x02, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00,0x00])
print(data as NSData) // "<01020a00 00000b00 0000>\n"
let beacon = XPLBeacon(data: data)
beacon.majorVersion // 1
beacon.minorVersion // 2
beacon.applicationHostId // 10
beacon.versionNumber // 11
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
929 次 |
| 最近记录: |