Ashley Mills Ashley Mills - 5 months ago 118
Swift Question

Swift 2 - UnsafeMutablePointer<Void> to object

If I have a method like:

func someMethod(contextPtr: UnsafeMutablePointer<Void>)


how do I get the object from the
contextPtr
?

func someMethod(contextPtr: UnsafeMutablePointer<Void>){
let object:MyObject = contextPtr.memory
}


gives:


'Void' is not convertible to 'MyObject'


What's the secret sauce




More detail:

What I'm actually doing here is setting up a global callback function for
SCNetworkReachability
:

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {

let r:Reachability = info.memory
}


and then adding the callback as follows:

var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
var s = self
withUnsafeMutablePointer(&s) {
context.info = UnsafeMutablePointer($0)
}
SCNetworkReachabilitySetCallback(reachability, callback, &context)

Answer

This should work: pass the object pointer as an opaque unmanaged pointer to the callback:

context.info = UnsafeMutablePointer(Unmanaged.passUnretained(myObject).toOpaque())
SCNetworkReachabilitySetCallback(reachability, callback, &context) 

and retrieve in the callback via:

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {

    let myObject = Unmanaged<MyObject>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

}

Of course this assumes that some strong reference to the object exists as long as the callback is installed, so that the object is not deallocated.

Update: Note that both conversions from object pointer to void pointer and back can be simplified if you are willing to use "unsafe" functions:

context.info = unsafeAddressOf(myObject)
// ...
myObject = unsafeBitCast(info, MyObject.self)

The generated assembly code is – as far as I can see – identical.

Update 2: See also How to cast self to UnsafeMutablePointer<Void> type in swift for more information about the "bridging" and some helper functions which can be used here.


Swift 3 update: Nullable pointers are now represented in Swift as optionals, and Unmanaged has been changed to use UnsafePointer:

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>?) {
    if let info = info {
        let myObject = Unmanaged<MyObject>.fromOpaque(info).takeUnretainedValue()
        // ...
    }
}
Comments