iosswifttypedefunsafemutablepointer

outputting a value to a typedef pointer in swift


I'm almost certain the title of this isn't correct but here goes...

I'm bridging to an Objective-C class to set a typedef. The bridge is set up and I'm able to declare the typedef var correctly.

In Objective-C I also called a method from the same class that, when called, output a value to the variable TestHandle.

var TestHandle : TESTHANDLE
TestInit(&TestHandle)

When I try this using Swift 5 I get this error:

Cannot convert value of type 'inout TESTHANDLE' (aka 'inout UnsafeMutableRawPointer') to expected argument type 'UnsafeMutablePointer<TESTHANDLE?>?' (aka 'Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>')

Any pointers?


Solution

  • Some observations:

    Swift has some rules about how & automatically bridges to the various pointer types, but to be frank, I don't understand them very well.

    As far as I know, the Swift pointer types cannot represent nil (0x000...000). To do that, they need to be wrapped within an optional. So when you see the type

    Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>
    

    It's actually two "semantic" parts:

    Optional<UnsafeMutablePointer<    Optional<UnsafeMutableRawPointer>    >>
    ↳ A nullable pointer to ...       ↳ ... something that's a nullable pointer of unspecified (void) type
    

    The reason you're getting your error is because &testHandle can only bridge your UnsafeMutableRawPointer to a Optional<UnsafeMutablePointer<UnsafeMutableRawPointer>>, but not the required Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>> (the difference is in that missing layer of "inner" nullability). To get around this, make your testHandle optional, yourself:

    var testHandle: TESTHANDLE? // a.k.a. Optional<TESTHANDLE>, a.k.a. Optional< UnsafeMutableRawPointer>
    

    Then, when you use the & operator, Swift will wrap your value in the required Optional<UnsafeMutablePointer< ... >> outter layer.

    typealias TESTHANDLE = UnsafeMutableRawPointer
    
    func testInit(_ p: UnsafeMutablePointer<TESTHANDLE?>?) {
        print("Success!")
    }
    
    var testHandle: TESTHANDLE? = nil
    testInit(&testHandle)