Adem Adem - 23 days ago 8
Objective-C Question

Convert unsinged char array from objective-c to UnsafeMutablePointer<UInt8> swift

I have an

unsigned char
array in .h file. and, also I have a function that takes unsigned char array as input. When I try to call this function in swift, it gets
UnsafeMutablePointer<UInt8>
. So, automatic objective-c to swift converter thinks
unsigned char
should be converted as
UnsafeMutablePointer<UInt8>
. But, I can not pass my variable to this function directly. Because I get,

Cannot convert value of type '(UInt8, UInt8, UInt8, UInt8, UInt8)' to expected argument type 'UnsafeMutablePointer<UInt8>!'


Length of this array is static. So, I can create

let key = UnsafeMutablePointer<UInt8>.allocate(capacity: 64);


and, also I can get value by
KEY.0
,
KEY.1
... etc. So, all I need is to create a for loop to read value from
KEY
and assign it to
key


for index in 1...64 {
key[index] = KEY[index];
}


but, this gives compilation error as:

Value of tuple type '(UInt8, UInt8, UInt8, UInt8, UInt8)' has no member 'index'


so, first question, how I can get any value from
KEY
by index. Second is, is there any easier way to convert a
unsigned char
array to
UnsafeMutablePointer<UInt8>

Answer

A C array

unsigned char ckey[64];

is imported as a tuple in Swift:

public var ckey: (UInt8, ..., UInt8)

and one cannot access the tuple elements by subscripting with an index. (Well, you can when using Mirror).

However:

  • The address of a C array is the same as the address of the first array element, and
  • for structures imported from C, Swift preserves the memory layout.

The latter was confirmed by Apple engineer Joe Groff:

... You can leave the struct defined in C and import it into Swift. Swift will respect C's layout.

Therefore you can pass the address of the first tuple element to the function:

f(key: &ckey.0)

Of course – as in C – the information about the size of the array is lost, so the array should be NUL-terminated, or f should know about the array size. Alternatively, pass the size as an additional argument to the function:

foo(key: &ckey.0, length: MemoryLayout.size(ofValue: ckey))
Comments