从 NSMutableData 添加和提取对象
Appending and extracting objects from NSMutableData
我需要创建一个包含多个参数的数据流,通过网络发送它,然后在收到数据时提取这些参数。
这就是创建我的数据的方式(我确定我的所有变量都包含一个值)
let dataToSend = NSMutableData()
var mType = Int32(messageType.rawValue)
var reqId = Int32(requestId)
dataToSend.appendDataWithUnsafeBytes(from: &mType, of: Int32.self)
dataToSend.appendDataWithUnsafeBytes(from: &reqId, of: Int32.self)
/* extra protocol data length. In version 0, this is0 as thereis no extra data.
In the future, if you need to add extra protocol data use this*/
var unUsedProtocol = Int32(0)
dataToSend.appendDataWithUnsafeBytes(from: &unUsedProtocol, of: Int32.self)
var encodedDataJson = !jsonString.isEmptyOrNil ? jsonString?.asciiValues : [UInt8]()
dataToSend.appendDataWithUnsafeBytes(from: &encodedDataJson, of: [UInt8]?.self)
var bData = bindaryData
dataToSend.appendDataWithUnsafeBytes(from: &bData, of: Data.self)
这是我的 appendDataWithUnsafeBytes NSMutableData 扩展。
extension NSMutableData {
func appendDataWithUnsafeBytes<T>(from element: inout T, of type: T.Type) {
let size = MemoryLayout.size(ofValue: element)
withUnsafeBytes(of: &element) { ptr in
let buffer = ptr.bindMemory(to: type)
if let address = buffer.baseAddress {
self.append(address, length: size)
} else {
VsLogger.logDebug("appendDataWithUnsafeBytes", "unable to get base address of pointer of type: \(type)")
}
}
}
}
这就是尝试提取它的方法(我得到了索引值和数据)
var messageTypeValue: Int32? = nil
var requestId: Int32? = nil
var encodedJsonData: Data? = nil
var binaryData: Data? = nil
let intSize = MemoryLayout<Int32>.size
let dataSize = MemoryLayout<Data>.size
var offset = index
bufferData.getBytes(&messageTypeValue, range: NSRange(location: offset, length: intSize))
offset += intSize //8
bufferData.getBytes(&requestId, range: NSRange(location: offset, length: intSize))
offset += intSize //12
/*skipping extra bytes (unsuedProtocol in sendMessageFunction). They come from a future version
that this code doesn't understand*/
offset += intSize //16
bufferData.getBytes(&encodedJsonData, range: NSRange(location: offset, length: dataSize))
offset += dataSize //32
bufferData.getBytes(&binaryData, range: NSRange(location: offset, length: dataSize))
我只能得到第一个值 (messageTypeValue),但对于其余的值,我要么得到 nil,要么得到不正确的数据。
谢谢!
***** 更新 *****
我通过如下修改我的发送和接收函数来让它工作。我寄到哪里。
let dataToSend = NSMutableData()
var mType = Int32(messageType.rawValue)
var reqId = Int32(requestId)
dataToSend.appendDataWithUnsafeBytes(from: &mType, of: Int32.self)
dataToSend.appendDataWithUnsafeBytes(from: &reqId, of: Int32.self)
/* estra protocol data length. In version 0, this is0 as thereis no extra data.
In the future, if you need to add extra protocol data use this*/
var unUsedProtocol = Int32(0)
dataToSend.appendDataWithUnsafeBytes(from: &unUsedProtocol, of: Int32.self)
var jsonData = Data(!jsonString.isEmptyOrNil ? jsonString!.asciiValues : [UInt8]())
dataToSend.appendDataWithUnsafeBytes(from: &jsonData, of: Data.self)
var bData = bindaryData
dataToSend.appendDataWithUnsafeBytes(from: &bData, of: Data.self)
我在哪里收到它
var offset = Int(index)
let int32Size = MemoryLayout<Int32>.size
let dataSize = MemoryLayout<Data>.size
let messageTypeValue = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
let requestId = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
//skip this one since it not used
//let unusedProtocol = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
let encodedJsonData = (bufferData.bytes + offset).load(as: Data.self)
offset += dataSize
let binaryData = bufferData.bytes.load(fromByteOffset: offset, as: Data.self)
数据应该始终正确对齐,但是有没有办法在 bufferData.bytes.load(fromByteOffset:as:)
上进行一些错误检查
如评论中所述,我强烈建议使用原生 Data
。
首先,您需要 将数字类型转换为 Data
,反之亦然。我添加了自定义 append
方法
extension Data {
init<T>(from value: T) {
self = Swift.withUnsafeBytes(of: value) { Data([=10=]) }
}
func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
var value: T = 0
guard count >= MemoryLayout.size(ofValue: value) else { return nil }
_ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: [=10=])} )
return value
}
mutating func append<T>(_ other: T) {
append(.init(from: other))
}
}
这是一个非常的数据集的简单版本,三个Int32
值和一个JSON数组
let mType : Int32 = 1
let reqId : Int32 = 2
let unUsedProtocol : Int32 = 0
let json = try! JSONEncoder().encode(["hello", "world"])
为方便起见,我省略了错误处理。在生产代码中,不鼓励 try!
。
Data
的巨大好处是它可以被视为一个集合类型,一个 (UInt8
) 字节的数组。要构建 Data
包,请转换数值并分别附加字节
var dataToSend = Data()
dataToSend.append(mType)
dataToSend.append(reqId)
dataToSend.append(unUsedProtocol)
dataToSend.append(json)
在接收端提取数值,这是一个辅助函数,它也会增加当前索引(如 inout
类型),字节长度由类型决定。函数 throws
如果索引超出范围且类型无法转换则出错。
enum ConvertDataError : Error { case outOfRange, invalidType}
func extractNumber<T : ExpressibleByIntegerLiteral>(from data : Data, type: T.Type, startIndex: inout Int) throws -> T {
let endIndex = startIndex + MemoryLayout<T>.size
guard endIndex <= data.endIndex else { throw ConvertDataError.outOfRange }
let subdata = data[startIndex..<endIndex]
guard let resultType = subdata.to(type: type) else { throw ConvertDataError.invalidType }
startIndex = endIndex
return resultType
}
获取数据包起始索引并提取Int32
个值
var index = dataToSend.startIndex
do {
let mType1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
let reqId1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
let unUsedProtocol1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
print(mType1, reqId1, unUsedProtocol1)
对于 json 部分,您需要长度,在本例中为 17 个字节
let jsonLength = json.count
let jsonOffset = index
index += jsonLength
let json1 = try JSONDecoder().decode([String].self, from: dataToSend[jsonOffset..<index])
print(json1)
} catch {
print(error)
}
我需要创建一个包含多个参数的数据流,通过网络发送它,然后在收到数据时提取这些参数。 这就是创建我的数据的方式(我确定我的所有变量都包含一个值)
let dataToSend = NSMutableData()
var mType = Int32(messageType.rawValue)
var reqId = Int32(requestId)
dataToSend.appendDataWithUnsafeBytes(from: &mType, of: Int32.self)
dataToSend.appendDataWithUnsafeBytes(from: &reqId, of: Int32.self)
/* extra protocol data length. In version 0, this is0 as thereis no extra data.
In the future, if you need to add extra protocol data use this*/
var unUsedProtocol = Int32(0)
dataToSend.appendDataWithUnsafeBytes(from: &unUsedProtocol, of: Int32.self)
var encodedDataJson = !jsonString.isEmptyOrNil ? jsonString?.asciiValues : [UInt8]()
dataToSend.appendDataWithUnsafeBytes(from: &encodedDataJson, of: [UInt8]?.self)
var bData = bindaryData
dataToSend.appendDataWithUnsafeBytes(from: &bData, of: Data.self)
这是我的 appendDataWithUnsafeBytes NSMutableData 扩展。
extension NSMutableData {
func appendDataWithUnsafeBytes<T>(from element: inout T, of type: T.Type) {
let size = MemoryLayout.size(ofValue: element)
withUnsafeBytes(of: &element) { ptr in
let buffer = ptr.bindMemory(to: type)
if let address = buffer.baseAddress {
self.append(address, length: size)
} else {
VsLogger.logDebug("appendDataWithUnsafeBytes", "unable to get base address of pointer of type: \(type)")
}
}
}
}
这就是尝试提取它的方法(我得到了索引值和数据)
var messageTypeValue: Int32? = nil
var requestId: Int32? = nil
var encodedJsonData: Data? = nil
var binaryData: Data? = nil
let intSize = MemoryLayout<Int32>.size
let dataSize = MemoryLayout<Data>.size
var offset = index
bufferData.getBytes(&messageTypeValue, range: NSRange(location: offset, length: intSize))
offset += intSize //8
bufferData.getBytes(&requestId, range: NSRange(location: offset, length: intSize))
offset += intSize //12
/*skipping extra bytes (unsuedProtocol in sendMessageFunction). They come from a future version
that this code doesn't understand*/
offset += intSize //16
bufferData.getBytes(&encodedJsonData, range: NSRange(location: offset, length: dataSize))
offset += dataSize //32
bufferData.getBytes(&binaryData, range: NSRange(location: offset, length: dataSize))
我只能得到第一个值 (messageTypeValue),但对于其余的值,我要么得到 nil,要么得到不正确的数据。
谢谢!
***** 更新 *****
我通过如下修改我的发送和接收函数来让它工作。我寄到哪里。
let dataToSend = NSMutableData()
var mType = Int32(messageType.rawValue)
var reqId = Int32(requestId)
dataToSend.appendDataWithUnsafeBytes(from: &mType, of: Int32.self)
dataToSend.appendDataWithUnsafeBytes(from: &reqId, of: Int32.self)
/* estra protocol data length. In version 0, this is0 as thereis no extra data.
In the future, if you need to add extra protocol data use this*/
var unUsedProtocol = Int32(0)
dataToSend.appendDataWithUnsafeBytes(from: &unUsedProtocol, of: Int32.self)
var jsonData = Data(!jsonString.isEmptyOrNil ? jsonString!.asciiValues : [UInt8]())
dataToSend.appendDataWithUnsafeBytes(from: &jsonData, of: Data.self)
var bData = bindaryData
dataToSend.appendDataWithUnsafeBytes(from: &bData, of: Data.self)
我在哪里收到它
var offset = Int(index)
let int32Size = MemoryLayout<Int32>.size
let dataSize = MemoryLayout<Data>.size
let messageTypeValue = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
let requestId = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
//skip this one since it not used
//let unusedProtocol = (bufferData.bytes + offset).load(as: Int32.self)
offset += int32Size
let encodedJsonData = (bufferData.bytes + offset).load(as: Data.self)
offset += dataSize
let binaryData = bufferData.bytes.load(fromByteOffset: offset, as: Data.self)
数据应该始终正确对齐,但是有没有办法在 bufferData.bytes.load(fromByteOffset:as:)
如评论中所述,我强烈建议使用原生 Data
。
首先,您需要 Data
,反之亦然。我添加了自定义 append
方法
extension Data {
init<T>(from value: T) {
self = Swift.withUnsafeBytes(of: value) { Data([=10=]) }
}
func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
var value: T = 0
guard count >= MemoryLayout.size(ofValue: value) else { return nil }
_ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: [=10=])} )
return value
}
mutating func append<T>(_ other: T) {
append(.init(from: other))
}
}
这是一个非常的数据集的简单版本,三个Int32
值和一个JSON数组
let mType : Int32 = 1
let reqId : Int32 = 2
let unUsedProtocol : Int32 = 0
let json = try! JSONEncoder().encode(["hello", "world"])
为方便起见,我省略了错误处理。在生产代码中,不鼓励 try!
。
Data
的巨大好处是它可以被视为一个集合类型,一个 (UInt8
) 字节的数组。要构建 Data
包,请转换数值并分别附加字节
var dataToSend = Data()
dataToSend.append(mType)
dataToSend.append(reqId)
dataToSend.append(unUsedProtocol)
dataToSend.append(json)
在接收端提取数值,这是一个辅助函数,它也会增加当前索引(如 inout
类型),字节长度由类型决定。函数 throws
如果索引超出范围且类型无法转换则出错。
enum ConvertDataError : Error { case outOfRange, invalidType}
func extractNumber<T : ExpressibleByIntegerLiteral>(from data : Data, type: T.Type, startIndex: inout Int) throws -> T {
let endIndex = startIndex + MemoryLayout<T>.size
guard endIndex <= data.endIndex else { throw ConvertDataError.outOfRange }
let subdata = data[startIndex..<endIndex]
guard let resultType = subdata.to(type: type) else { throw ConvertDataError.invalidType }
startIndex = endIndex
return resultType
}
获取数据包起始索引并提取Int32
个值
var index = dataToSend.startIndex
do {
let mType1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
let reqId1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
let unUsedProtocol1 = try extractNumber(from: dataToSend, type: Int32.self, startIndex: &index)
print(mType1, reqId1, unUsedProtocol1)
对于 json 部分,您需要长度,在本例中为 17 个字节
let jsonLength = json.count
let jsonOffset = index
index += jsonLength
let json1 = try JSONDecoder().decode([String].self, from: dataToSend[jsonOffset..<index])
print(json1)
} catch {
print(error)
}