0

私は構造体オブジェクトを持っています。入力がペイロードであるメソッド。現在、という名前の mutableData を作成していpacketます。その可変バイトは ICMPHeader 構造体を参照しています。

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
}

可変バイトは正常に構造体にバインドされ、値も構造体で更新されていICMPHeaderます。

問題は、構造体の値を変更しても可変データの値が変更されないことpacketです。

また、構造体を作成した後にパケットを再作成しようとすると、クラッシュします。

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

1 に答える 1

0

XCode 8.1 Swift リリース ノートで答えを見つけました。

構造体オブジェクトicmpPtrに変更を加えた後、それをバッファー ポインターに戻しました。

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

したがって、新しい Data オブジェクトを作成する代わりに、バイトを置き換えたところ、魅力的に機能しました。

ドキュメントに従って:

XCode 8.1 リリース ノート: https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html Swift セクション:

新しい withUnsafeBytes(of:) 関数は、値のメモリ内表現を UnsafeRawBufferPointer として公開します。この例では、異種の構造体を同種のバイト配列にコピーします。

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
}
于 2016-11-03T16:59:39.600 に答える