2016-11-02 3 views
0

У меня есть объект struct. И метод, вход которого - полезная нагрузка. Теперь я создаю mutableData с именем packet, и это изменяемые байты относятся к структуре ICMPHeader.Байт NSMutableData для UnsafeMutableRawPointer не обновляет значение mutableData

struct ICMPHeader { 
    var type:UInt8 
    var code:UInt8 
    var checksum:UInt16 
    var identifier:UInt16 
    var sequenceNumber:UInt16 
}; 


func createPacket(payload:NSData) -> NSData(){ 
    var packet:NSMutableData? 
    var icmpPtr:ICMPHeader = ICMPHeader(type: 0, code: 0, checksum: 0, identifier: 0, sequenceNumber: 0) 
    packet = NSMutableData(length: Int(MemoryLayout<ICMPHeader>.size + payload.length)) 

    if packet != nil { 

     icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee 

     icmpPtr.type = type 
     icmpPtr.code = 0 
     icmpPtr.checksum = 0 
     icmpPtr.identifier = CFSwapInt16BigToHost(identifier) 
     icmpPtr.sequenceNumber = CFSwapInt16HostToBig(identifier) 
     memcpy(&icmpPtr + 1, payload.bytes, payload.length) 

     if (requiresChecksum) { 
      icmpPtr.checksum = in_cksum(packet!.bytes, bufferLen: packet!.length); 
     } 

    } 
    return packet 
} 

Mutable байты успешно получать переплетены на структуру и значение также получать обновленный в структурах ICMPHeader.

Проблема в изменении значений в структуре не изменяет значение изменяемых данных packet.

И если, я пытаюсь воссоздать пакет после создания структуры, то он сбой.

package = NSMutableData(bytes: unsafeBitCast(icmpPtr, to: UnsafeMutableRawPointer.self), length: Int(MemoryLayout<ICMPHeader>.size + payload.length)) 

ответ

0

Я нашел ответ в примечаниях к выпуску XCode 8.1 Swift.

После внесения изменений в объект struct icmpPtr Я изменил его обратно на указатель буфера.

var byteBuffer = [UInt8]() 
withUnsafeBytes(of: &icmpPtr) { 
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes 
} 
package.replaceBytes(in: NSMakeRange(0, byteBuffer.count), withBytes: byteBuffer) 

Таким образом, вместо создания нового объекта данных, я заменил байты и он работал как шарм.

Согласно документации:

XCode 8.1 Примечание к выпуску: https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html Swift Раздел:

Нового withUnsafeBytes (из :) функции предоставляет в памяти представления значения в качестве UnsafeRawBufferPointer. Этот пример копирует гетерогенной Struct в однородную массив байт:

struct Header { 
var x: Int 
var y: Float 
} 

var header = Header(x: 0, y: 0.0) 
var byteBuffer = [UInt8]() 

withUnsafeBytes(of: &header) { 
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes 
} 

новый метод, лежащий в основе Array.withUnsafeBytes выставляет буфера массива в качестве UnsafeRawBufferPointer. Этот пример копирует массив из целых чисел в массив байтов:

let intArray = [1, 2, 3] 
var byteBuffer = [UInt8]() 

intArray.withUnsafeBytes { 
    (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes 
} 

Так что окончательное внедрение является

struct ICMPHeader { 
    var type:UInt8 
    var code:UInt8 
    var checksum:UInt16 
    var identifier:UInt16 
    var sequenceNumber:UInt16 
}; 


func createPacket(payload:NSData) -> NSData(){ 
    var packet:NSMutableData? 
    var icmpPtr:ICMPHeader = ICMPHeader(type: 0, code: 0, checksum: 0, identifier: 0, sequenceNumber: 0) 
    packet = NSMutableData(length: Int(MemoryLayout<ICMPHeader>.size + payload.length)) 

    if packet != nil { 

     icmpPtr = packet!.mutableBytes.assumingMemoryBound(to: ICMPHeader.self).pointee 

     icmpPtr.type = type 
     icmpPtr.code = 0 
     icmpPtr.checksum = 0 
     icmpPtr.identifier = CFSwapInt16BigToHost(identifier) 
     icmpPtr.sequenceNumber = CFSwapInt16HostToBig(identifier) 
     memcpy(&icmpPtr + 1, payload.bytes, payload.length) 

     if (requiresChecksum) { 
      icmpPtr.checksum = in_cksum(packet!.bytes, bufferLen: packet!.length); 
     } 

     var byteBuffer = [UInt8]() 
     withUnsafeBytes(of: &icmpPtr) { 
     (bytes: UnsafeRawBufferPointer) in byteBuffer += bytes 
     } 
     packet.replaceBytes(in: NSMakeRange(0, byteBuffer.count), withBytes: byteBuffer) 

    } 
    return packet 
} 
Смежные вопросы