Search code examples
castingswiftnsdataswift-playground

How does NSData(bytes:length:) convert [Byte] to UnsafePointer<Void> in Swift?


Playing with raw data in Swift I came across something I don't understand.
NSData has a constructor:

init(bytes: UnsafePointer<Void>, length: Int)

where the first bytes parameter is clearly of UnsafePointer type.
However, if I pass [Byte] object to this constructor, not only does the compiler not complain, but it works ok.
But if I try to cast [Byte] to UnsafePointer, I fail.
How does this work?

For example (you can try it in Playgrounds):

let buffer: [Byte] = [0x00, 0xff]
let data = NSData(bytes: buffer, length: buffer.count) // no error
data.description

var pointer: UnsafePointer<Void>
// comment this line to avoid compiler error
pointer = buffer // error

I know I can do

UnsafePointer<Void>(buffer)

but my question is, what does NSData constructor do implicitly, that I don't have to do that.


Solution

  • Swift maps its own types to C pointers when you're calling a C function that requires them. Apple has a bit of documentation on this interaction: Interacting with C APIs.

    In short, when you're calling a function that takes an UnsafePointer<Type>, it can accept nil, an inout variable of that type, an array of that type (i.e., [Type], what you're using), or one of the generic Swift pointer types. A function taking UnsafePointer<Void> can take any of those, with no constraint on the type at all, so you need to read the function's documentation to see what it expects/will return.