Unsafe pointers in Swift: Conversion to and from a COpaquePointer (and CFunctionPointer) (Part II, Xcode 6 Beta 6; update Swift 3, Xcode 8)


The unsafe pointers in Swift posts, of which this is the second, are a tentative toe-dipping into the world of connecting Swift with the C functions provided in Apple's Darwin -> C -> stdlib header file. As such, this post is neither exhaustive nor expert, I am simply trying to fill a void where I find little else to work with in my experimentations.

You should read the code found here as if it were written in someone's personal notebook and never use it without first understanding it and satisfying yourself that it works correctly.

COpaquePointer

With all of this in mind, here is my code for today, fulfilling the conversion of an UnsafeMutablePointer to and from a COpaquePointer:
let str = "Hello, pointer"
let ps = UnsafeMutablePointer<String>.alloc(1) // allocate memory for one String instance
ps.initialize(str) // intialize with a value
let cps = COpaquePointer(ps) // convert UnsafeMutablePointer to COpaquePointer
let nps = UnsafeMutablePointer<String>(cps) // convert COpaquePointer to UnsafeMutablePointer

nps.memory // returns "Hello, pointer"

ps.destroy() // return pointer to an unintialized state
ps.dealloc(1) // deallocate memory

Swift 3 (Xcode 8)

let ps = UnsafeMutablePointer.allocate(capacity: 1) // allocate memory for one String instance
ps.initialize(to: str) // intialize with a value
let cps = OpaquePointer(ps) // convert UnsafeMutablePointer to COpaquePointer
let nps = UnsafeMutablePointer(cps) // convert COpaquePointer to UnsafeMutablePointer

nps.pointee // returns "Hello, pointer"
ps.deinitialize() // return pointer to an unintialized state
ps.deallocate(capacity: 1) // deallocate memory

CFunctionPointer

As usual we can go further and among the Swift types you'll find something called a CFunctionPointer as well. So while we're here we may as well have a go at creating one of those for completeness, because in order to create a CFunctionPointer you need a COpaquePointer from which to initialise it:
let a:() -> String = {
    return "Hello from C"
}

let p = UnsafeMutablePointer<() -> String>.alloc(1) // allocate memory for function
p.initialize(a) // initialize with value

let cp = COpaquePointer(p) // convert UnsafeMutablePointer to COpaquePointer
let fp = CFunctionPointer<() -> String>(cp) // convert COpaquePointer to CFunctionPointer
let ncp = COpaquePointer(fp) // convert CFunctionPointer to COpaquePointer
let np = UnsafeMutablePointer<() -> String>(ncp) // convert COpaquePointer to UnsafeMutablePointer

np.memory() // calls anonymous function and returns "Hello from C"

p.destroy() // return pointer to an unintialized state
p.dealloc(1) // deallocate memory

Swift 3, Xcode 8

let a:() -> String = {
    return "Hello from C"
}

let p = UnsafeMutablePointer<() -> String>.allocate(capacity: 1) // allocate memory for function
p.initialize(to: a) // initialize with value

let cp = OpaquePointer(p) // convert UnsafeMutablePointer to COpaquePointer

let fp = UnsafeMutablePointer<@convention(c) () -> String>(cp) // convert COpaquePointer to CFunctionPointer
let ncp = OpaquePointer(fp) // convert CFunctionPointer to COpaquePointer
let np = UnsafeMutablePointer<() -> String>(ncp) // convert COpaquePointer to UnsafeMutablePointer

p.move()() // calls anonymous function and returns "Hello from C" and deinitializes
p.deallocate(capacity: 1) // deallocate memory
Warning: for education purposes only!

Comments

  1. Hi

    I am trying to call the following Object C method from Swift but can't seem to pass in the string in the correct format. It appears to be expecting an UnsafeMutablePointer. Any help would be appreciated.

    + (BOOL) Check:(NSString* __strong *)postcode

    ReplyDelete

Post a Comment