Search code examples
pointersswiftnsdata

Working with NSData in swift


So I've figured out how to extract NSData in swift but i'm getting confused with regards to setting it:

var testBytes : [Byte] = [0x14, 0x00, 0xAB, 0x45, 0x49, 0x1F, 0xEF, 0x15,     
                          0xA8, 0x89, 0x78, 0x0F, 0x09, 0xA9, 0x07, 0xB0,
                          0x01, 0x20, 0x01, 0x4E, 0x38, 0x32, 0x35, 0x56,
                          0x20, 0x20, 0x20, 0x00]

var msgData = NSData(bytes: testBytes, length: testBytes.count)

println("\(msgData)")


var length : Int = testBytes.count

var out: NSInteger = 0

let ptr = UnsafePointer<UInt8>(msgData.bytes)
var bytes = UnsafeBufferPointer<UInt8>(start: ptr, count: 28)

So if i want to access a specific byte I can get it with something like:

let targetAddress = UInt32(bytes[2]) << 16 |
    UInt32(bytes[3]) << 8 |
    UInt32(bytes[4]) << 0

Now say I wanted to set a value with something like:

bytes[11] = UInt8(UInt32(bytes[11]) | 0x0FF)

I get an error of Cannot assign the result of this expression). I tried also using &bytes[11] which doesn't seem to fly either.

I'm assuming this is because the array uses an unsafe buffer pointer. Is there an easy call that I've some how glossed over to make the assignment work correctly?


Solution

  • If you want to modify the bytes retrieved from the NSData object, then you should copy the bytes into a separate array

    var bytes = [UInt8](count: msgData.length, repeatedValue: 0)
    msgData.getBytes(&bytes, length: bytes.count)
    
    bytes[11] = UInt8(UInt32(bytes[11]) | 0x0FF)
    

    NSData is an immutable object, and

    let ptr = UnsafePointer<UInt8>(msgData.bytes)
    

    is a constant pointer, so you must not modify the pointed-to data.

    Alternatively, use a mutable data object from the beginning:

    var msgData = NSMutableData(bytes: testBytes, length: testBytes.count)
    
    let ptr = UnsafeMutablePointer<UInt8>(msgData.mutableBytes)
    var bytes = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: msgData.length)
    
    bytes[11] = UInt8(UInt32(bytes[11]) | 0x0FF)
    

    Note the usage of msgData.mutableBytes instead of msgData.bytes. This will modify the data in msgData directly.