Search code examples
swift3xcode8unsafemutablepointer

Swift3 changes to UnsafeMutablePointer


I am porting one of my iOS Apps to Swift3 / Xcode8. I have embedded a C library, which expects a function parameter of type:

char ***

In Swift2.3 this was translated into a:

UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

So i could declare that pointer in my swift code like that:

let myPointer = UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>.alloc(1)

This worked well until i updated to Xcode8 with Swift3, now i am getting a compiler error:

Cannot convert value of type 'UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>' to expected argument type 'UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?>!'

Can i anybody help me to understand the changes in swift3? What does this Optional, Optional, Implicit Unwrapped Optional (?) mean in this context and how i can i declare a pointer with this type?


Solution

  • Try

    let myPointer = UnsafeMutablePointer<
        UnsafeMutablePointer<
        UnsafeMutablePointer<Int8>?>?>.allocate(capacity: 1)
    

    Alternatively you could also use the _Nonnull annotation to keep the pointer as non-optional. Suppose the C function is void setPtr(char ***). You could write its declaration available to Swift via a bridging header as follows:

    void setPtr(char * _Nonnull * _Nonnull * _Nonnull);
    

    Then in your Swift code you can do something like this:

    let myPointer = UnsafeMutablePointer<
            UnsafeMutablePointer<
            UnsafeMutablePointer<Int8>>>.allocate(capacity: 1)
    setPtr(myPointer)
    let myInt = myPointer.pointee.pointee.pointee
    

    But what if setPtr(char *** ptr) in C code, where _Nonnull is not usable, does something like

    *ptr = NULL;
    

    ? Then the Swift code will crash at runtime. However, using optionals you don't need the _Nonnull annotation in the declaration of setPtr(), your Swift code becomes

    let myPointer = UnsafeMutablePointer<
            UnsafeMutablePointer<
            UnsafeMutablePointer<Int8>?>?>.allocate(capacity: 1)
    setPtr(myPointer)
    let myInt = myPointer.pointee?.pointee?.pointee
    

    and it won't crash at runtime. Thus the approach with optionals, enforced by Swift3 when you don't use _Nonnull, is safer.