Search code examples
objective-cswiftnsdata

How to pass const void *bytes to an Objective-C block from Swift


I'm writing some Swift (1.2) code that calls an Objective-C library (transcribing some earlier Objective-C code). It's not clear how it's supposed to work. I've tried a bunch of variations, and nothing satisfies the compiler. Here's the Objective-C code I started with:

// Objective-C

NSData *fileData = //

const void *bytes = fileData.bytes;
unsigned int bufferSize = 1024; //Arbitrary

[object writeDataWithBlock:
 ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) {
     for (NSUInteger offset = 0; offset <= fileData.length; offset += bufferSize) {
         unsigned int size = (unsigned int)MIN(fileData.length - i, bufferSize);
         writeData(&bytes[i], size);
     }

     return YES;
 }];

So far, I've gotten as far as this Swift code:

// Swift

let fileData = //

let ptr = UnsafePointer<UInt8>(fileData.bytes)
let bufferSize = 1024 // Arbitrary

object.writeDataWithBlock() { (writeData, actionError) -> Bool in
    for var offset = 0; offset <= fileData.length; offset += bufferSize {
        let size = CUnsignedInt(min(fileData.length - offset, bufferSize))
        writeData(UnsafePointer<Void>(ptr[offset]), size)
    }

    return true
}

That's giving me this error:

Cannot find an initializer for type 'UnsafePointer' that accepts an arguments list of type '(UInt8)'

When I remove the UnsafePointer<Void> conversion to do a more direct translation, yielding this line:

writeData(&ptr[offset], size)

I get this error, pointing at the & character:

Type of expression is ambiguous without more context

Without the &, it yields a UInt8, giving me this error:

Cannot invoke 'writeData' with an argument list of type '(Uint8, UInt32)'

What do I need to do to read the bytes out of the NSData sequentially and pass them onto another method?


Solution

  • Pointer arithmetic should (and does) get you the results you're looking for.

    let fileData = //
    let bufferSize = 1024 // Arbitrary
    
    object.writeDataWithBlock() { (writeData, actionError) -> Bool in
        for var offset = 0; offset <= fileData.length; offset += bufferSize {
            let size = CUnsignedInt(min(fileData.length - offset, bufferSize))
            writeData(fileData.bytes + offset, size)
        }
    
        return true
    }