因此,我有来自某些硬件的格式良好的数据流。该流由一堆 8 位数据块组成,其中一些数据旨在形成 32 位整数。这一切都很好。数据继续移动,现在我想将序列打包。
数据实际上是一个连续的字节块,其中的各个部分映射到有用的数据。因此,例如,第一个字节是确认码,接下来的四个字节表示具有某种特定于应用程序含义的 UInt32,后面是表示 UInt16 的两个字节,依此类推,有几十个字节。
我发现了两种不同的方法来做到这一点,这两种方法似乎都有点……过度紧张。当你靠近金属时,可能就会发生这种情况。
但是——这两种代码习惯通常是人们应该期望做的事情吗?或者我错过了一些更紧凑的东西?
// data : Data exists before this code, and has what we're transforming into UInt32
// One Way to get 4 bytes from Data into a UInt32
var y : [UInt8] = [UInt8](repeating:UInt8(0x0), count: 4)
data.copyBytes(to: &y, from: Range(uncheckedBounds: (2,6)))
let u32result = UnsafePointer(y).withMemoryRebound(to: UInt32.self, capacity: 1, {
$0.pointee
})
// u32result contains the 4 bytes from data
// Another Way to get 4 bytes from Data into a UInt32 via NSData
var result : UInt32 = 0
let resultAsNSData : NSData = data.subdata(in: Range(uncheckedBounds: (2,6))) as NSData
resultAsNSData.getBytes(&result, range: NSRange(location: 0, length: 4))
// result contains the 4 bytes from data
从格式正确的数据对象创建 UInt32 数组。
// Create sample data
let data = "foo".data(using: .utf8)!
// Using pointers style constructor
let array = data.withUnsafeBytes {
[UInt32](UnsafeBufferPointer(start: $0, count: data.count))
}
// Create sample data
let data = "foo".dataUsingEncoding(NSUTF8StringEncoding)!
// Using pointers style constructor
let array = Array(UnsafeBufferPointer(start: UnsafePointer<UInt32>(data.bytes), count: data.length))
我发现了另外两种方法可以做到这一点,这让我相信有很多方法可以做到这一点,我想这很好。 Ray Wenderlich
以某种方式描述了另外两种方法将此代码放入您的 Xcode 游乐场中将揭示这两个其他习惯用法。
do {
let count = 1 // number of UInt32s
let stride = MemoryLayout<UInt32>.stride
let alignment = MemoryLayout<UInt32>.alignment
let byteCount = count * stride
var bytes : [UInt8] = [0x0D, 0x0C, 0x0B, 0x0A] // little-endian LSB -> MSB
var data : Data = Data.init(bytes: bytes) // In my situtation, I actually start with an instance of Data, so the [UInt8] above is a conceit.
print("---------------- 1 ------------------")
let placeholder = UnsafeMutableRawPointer.allocate(bytes: byteCount, alignedTo:alignment)
withUnsafeBytes(of: &data, { (bytes) in
for (index, byte) in data.enumerated() {
print("byte[\(index)]->\(String(format: "0x%02x",byte)) data[\(index)]->\(String(format: "0x%02x", data[index])) addr: \(bytes.baseAddress!+index)")
placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)
}
})
let typedPointer1 = placeholder.bindMemory(to: UInt32.self, capacity: count)
print("u32: \(String(format: "0x%08x", typedPointer1.pointee))")
print("---------------- 2 ------------------")
for (index, byte) in bytes.enumerated() {
placeholder.storeBytes(of: byte, toByteOffset: index, as: UInt8.self)
// print("byte \(index): \(byte)")
print("byte[\(index)]->\(String(format: "0x%02x",byte))")
}
let typedPointer = placeholder.bindMemory(to: UInt32.self, capacity: count)
print(typedPointer.pointee)
let result : UInt32 = typedPointer.pointee
print("u32: \(String(format: "0x%08x", typedPointer.pointee))")
}
有输出:
---------------- 1 ------------------
byte[0]->0x0d data[0]->0x0d addr: 0x00007fff57243f68
byte[1]->0x0c data[1]->0x0c addr: 0x00007fff57243f69
byte[2]->0x0b data[2]->0x0b addr: 0x00007fff57243f6a
byte[3]->0x0a data[3]->0x0a addr: 0x00007fff57243f6b
u32: 0x0a0b0c0d
---------------- 2 ------------------
byte[0]->0x0d
byte[1]->0x0c
byte[2]->0x0b
byte[3]->0x0a
168496141
u32: 0x0a0b0c0d
这是要点。
这是一个采用 Swift
Data
并支持从 Swift 中读出多种数字数据类型的方法 Data
func read<T: FixedWidthInteger>(data: Data, offset: Int, length tSize: Int) -> T {
var value: T = 0
withUnsafeMutableBytes(of: &value, { bytes -> Void in
data.withUnsafeBytes { rawBytes -> Void in
memcpy(bytes.baseAddress!, rawBytes.baseAddress!.advanced(by: offset), tSize)
}
})
return value
}
使用数据:让我们将几个不同的 Swift 数字类型添加到缓冲区中
var value1Signed: Int64 = -1234567
var value1Unsigned: UInt64 = 1234567
let value1Size = MemoryLayout<Int64>.size
var value2Signed: Int32 = -12345
var value2Unsigned: UInt32 = 12345
let value2Size = 4
var value3Signed: Int16 = -123
var value3Unsigned: UInt16 = 123
let value3Size = MemoryLayout<Int16>.size
let ptr: UnsafeMutableRawPointer = malloc(value1Size * 2 +
value2Size * 2 +
value3Size * 2)
var offset: Int = 0
memcpy(ptr.advanced(by: offset), &value1Signed, value1Size)
memcpy(ptr + offset + value1Size, &value1Unsigned, value1Size)
offset += value1Size * 2
memcpy(ptr.advanced(by: offset), &value2Signed, value2Size)
memcpy(ptr + offset + value2Size, &value2Unsigned, value2Size)
offset += value2Size * 2
memcpy(ptr.advanced(by: offset), &value3Signed, value3Size)
memcpy(ptr + offset + value3Size, &value3Unsigned, value3Size)
offset += value3Size * 2
将示例缓冲区复制到 Swift
Data
并测试读取方法
let data = Data(bytes: ptr, count: offset)
read(data: data, offset: 0, length: 8) as Int64 // -1234567
read(data: data, offset: 0 + 8, length: 8) as UInt64 // 1234567
read(data: data, offset: 8 + 8, length: 4) as Int32 // -12345
read(data: data, offset: 8 + 8 + 4, length: 4) as UInt32 // 12345
read(data: data, offset: 8 + 8 + 4 + 4, length: 2) as Int16 // -123
read(data: data, offset: 8 + 8 + 4 + 4 + 2, length: 2) as UInt16 // 123
你也可以直接使用
memcpy
方法从内存指针中读取,而不是使用 Swift Data
,就像这样
var value: Int16 = 0
memcpy(&value, ptr.advanced(by: 8 + 8 + 4 + 4), 2)
print(value)
let a = [ 0x00, 0x00, 0x00, 0x0e ]
let b = a[0] << 24 + a[1] << 16 + a[2] << 8 + a[3]
print(b) // will print 14.
我应该描述这个操作吗?