Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 782
Ashley Mills Avatar asked Jun 11 '15 16:06

Ashley Mills


1 Answers

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 (Xcode 8 beta 6):

var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())

// ...

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    if let info = info {
        let myObject = Unmanaged<MyObject>.fromOpaque(info).takeUnretainedValue()
        // ...
    }
}
like image 128
Martin R Avatar answered Oct 17 '22 22:10

Martin R