Sunday, November 25, 2018

UnsafePointer and UnsafeMutablePointer

When calling objective c function from swift code, the objective c type needs mapping to swift type.

For primary type used as value type parameter, like int, NSString*, they can be mapped to primary type of swift, as Int32, String.

For NSObject inherited interface types, as they are always used as reference type (pointer), so they can also mapped to the corresponding swift types, or keep Objective C original type. For example, NSArray will map to [Any], NSDictionary will map to [HashTable: Any]. But NSMutableDictionary and NSMutableArray will keep the same type name in swift code.

For C struct when used as value type parameter, the same type name will be in swift code.

The thing gets complex when pointer are used for primary type and c struct.

When pointer is used, if the pointer is defined with const, which means the object pointed by the pointer cannot be changed, then the parameter type will mapped to UnsafePointer<Type>; otherwise, it will be mapped to UnsafeMutablePointer<Type>. The major difference between UnsafePointer and UnsafeMutablePointer is UnsafePointer.pointee is read-only, while UnsafeMutablePointer.pointee is writable.

Objective C

-(int) sump:(int*)vp1 add:(const int*)vp2;
maps to

func sump(_ vp1: UnsafeMutablePointer<Int32>!, add vp2:UnsafePointer<Int32>!) -> Int32


If an objective c function only takes a pointer parameter, and on swift side an swift object is passed to the function, then you can use helper method of withUnsafePointer or withUnsafeMutablePointer to simplify the logic. As shown below, the input parameter b is converted to UnsafePointer bb in the function block.


var  b : Int32 = 10
let result :Int32 = withUnsafePointer(to: b) { (bb: UnsafePointer<Int32>) -> Int32 in
      var t : Int32 = bb.pointee
      let mt : UnsafeMutablePointer<Int32>? = UnsafeMutablePointer<Int32>(&t)
  
      let m : Int32 = o.sump(mt, add:bb)
      return m
}

after the code block returns, b is still 10.


The similar function can also be called using withUnsafeMutablePointer, which will allow to update b's value if it is updated inside the objective c function as shown below

var  b : Int32 = 10
let result2 = withUnsafeMutablePointer(to: &b) { (bb: UnsafeMutablePointer<Int32>) -> Int32 in
          
    let mt : UnsafePointer<Int32>? = UnsafePointer<Int32>(bb)
  
    let m : Int32 = o.sump(bb, add:mt)
    return m
}

if sump function updates first parameter's value, then after the above code block returns, the variable b's value will be changed to the updated value.


No comments:

Post a Comment