29

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) 
2
  • What do you pass when you you call the method? And why is it passed as void pointer? Commented Jun 11, 2015 at 16:57
  • I was trying to simplify the code a little - I've added some more detail Commented Jun 11, 2015 at 17:02

2 Answers 2

45

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() // ... } } 
Sign up to request clarification or add additional context in comments.

14 Comments

@AshleyMills: Nice to see that you could use it in your Reachability project!
That was the final key to the puzzle!
just noticed your update. Nice idea, but unfortunately this doesn't work for the problem I was trying to solve as unsafeAddressOf requires AnyObject and SCNetworkReachabilityContext is a struct
Nice solution. I'm surprised how long it took me to find this, though. Given the reliance of certain low-level API's on unsafe pointers you'd think that a lot of people would need to know this!
@yesthisisjoe: It seems that I updated the code using a Swift 3 preview release from swift.org. It does now compile with Xcode 8, can you check it again? Thanks for your feedback!
|
-2
struct S { var i: Int = 10 } var first = S() func foo(contextPtr: UnsafeMutablePointer<Void>){ let pS = UnsafeMutablePointer<S>(contextPtr) pS.memory.i = 100 } print(first.i) // 10 foo(&first) print(first.i) // 100 

if we need pass as UnsafeMutablePointer self to async function

import XCPlayground XCPlaygroundPage.currentPage.needsIndefiniteExecution = true import Foundation // can be struct, class ... class C { let queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT) var s: String = "" func foo() { var c = self dispatch_async(queue) { () -> Void in f(&c) } } } func f(pV: UnsafeMutablePointer<Void>) { let pC = UnsafeMutablePointer<C>(pV) sleep(1) print(pC.memory.s) } var c1: C? = C() c1!.s = "C1" c1!.foo() // C1 var c2: C? = C() c2!.s = "C2" c2!.foo() // C2 c1 = nil c2 = nil print("test") 

1 Comment

Your sample code is different than the question, though, because C.foo() calls f() synchronously, so c stays allocated. In the original question, f() is an asynchronous callback function, and so c would be released before f() is called.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.