How can I use Swift objects as UnsafeMutablePointer<OpaquePointer?> to a C function

1.8k Views Asked by At

There is a C struct:

struct SomeStruct;

And there is a C function which uses this struct as double pointer parameter:

C_exampleFunction(struct SomeStruct** someClass)

I would like to pass any Swift class or object to this function in order to use its functionality. However the C function on the Swift side only accepts UnsafeMutablePointer as argument:

mySwiftFunction(for obj: AnyObject) {
   let objUnsafeMutableRawPointer = Unmanaged.passUnretained(obj).toOpaque()
   let objOpaquePointer = OpaquePointer(objUnsafeMutableRawPointer)
   let someClassArg = UnsafeMutablePointer<OpaquePointer?>(objOpaquePointer)

   C_exampleFunction(someClassArg)
}

The code has always produce some memory error even if I deallocate the pointers. My main question is how can I add objects as UnsafeMutablePointer to a C function like this above?

I checked these sources (but no luck):

Error what I get is:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x6ba571ac0)

Thank you for your answers, feedbacks and especially your time in advance.

1

There are 1 best solutions below

0
On

I think one can do relatively little with a Swift object passed to a C function via an incomplete type pointer, but if you need to do that, you are on a right track.

One problem I see with the code in your question is the line

let someClassArg = UnsafeMutablePointer<OpaquePointer?>(objOpaquePointer)

Here someClassArg is still a pointer to obj that was passed in to mySwiftFunction(), it's just cast to a different pointer type. However, C_exampleFunction() needs a pointer to a pointer to obj. Thus the code is most likely going to crash.

You can resolve this by replacing the problematic line with

let someClassArg = UnsafeMutablePointer<OpaquePointer?>.allocate(capacity: 1)
someClassArg.pointee = objOpaquePointer

There are other approaches, too. For example, you could pass objOpaquePointer using inout syntax; it would need to be a var for that to work, though. You could also avoid using Unmanaged like this:

let objUnsafeMutablePtr = UnsafeMutablePointer<AnyObject>.allocate(capacity: 1)
objUnsafeMutablePtr.pointee = obj
var objOpaquePtr : OpaquePointer! = OpaquePointer(objUnsafeMutablePtr)
C_exampleFunction(&objOpaquePtr) 

(here we pass the opaque pointer as inout).

Regardless of which approach is taken, one should be very careful about the lifetime of obj. For example, if you use Unmanaged, you may want to use passRetained() (and then takeRetainedValue() when retrieving the object), but that depends on your use case.

Here is another helpful resource about manual memory management:

https://developer.apple.com/documentation/swift/swift_standard_library/manual_memory_management