53

Trying to pass "self" to a C function in swift, when calling following code:

var callbackStruct : AURenderCallbackStruct = 
    AURenderCallbackStruct.init(
      inputProc: recordingCallback,
      inputProcRefCon: UnsafeMutablePointer<Void>
    )

What is the ideal way to cast "self" to a UnsafeMutablePointer type here?

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
Peter Peng
  • 1,910
  • 1
  • 27
  • 37
  • How are you assigning self to inputProcRefCon? Hope you have gone through this- https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html – Shripada Oct 23 '15 at 04:33
  • 1
    Another example: http://stackoverflow.com/questions/33260808/swift-proper-use-of-cfnotificationcenteraddobserver-w-callback/33262376#33262376. – Martin R Oct 23 '15 at 04:38
  • Actually @MartinR I think your answer here is more helpful: http://stackoverflow.com/a/30788165/341994 – matt Oct 23 '15 at 04:47
  • @matt: But that is exactly the thread that I used as a "duplicate". I added another link in a comment because it shows a complete self-contained example, even if the question is different. – Perhaps I did not get what you meant? – Martin R Oct 23 '15 at 06:54
  • Got it. Cheers guys. – Peter Peng Oct 23 '15 at 07:00
  • @MartinR Right, I was just saying that the comment-link example is likely to confuse the OP more than help. Your duplicate-link example code is simple, clear, and direct. - And I have no idea what it does or why we have to jump through these elaborate hoops just in order to talk to C! :) – matt Oct 23 '15 at 13:39
  • @MartinR it seems to me that this is what `withUnsafeMutablePointer` is for, and I've added an answer that demonstrates. If I'm wrong, please tell me and I'll delete it. But I just can't believe that you have jump through these Unmanaged and Opaque hoops just to do this. – matt Oct 23 '15 at 15:26

4 Answers4

108

An object pointer (i.e. an instance of a reference type) can be converted to a UnsafePointer<Void> (the Swift mapping of const void *, UnsafeRawPointer in Swift 3) and back. In Objective-C you would write

void *voidPtr = (__bridge void*)self;
// 
MyType *mySelf = (__bridge MyType *)voidPtr;

(See 3.2.4 Bridged casts in the Clang ARC documentation for the precise meaning of these casts.)

Swift has an Unmanaged type for that purpose. It is a bit cumbersome to use because it works with COpaquePointer instead of UnsafePointer<Void>. Here are two helper methods (named after the Objective-C __bridge cast):

func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
    return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
    // return unsafeAddressOf(obj) // ***
}

func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
    return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
    // return unsafeBitCast(ptr, T.self) // ***
}

The "complicated" expression is only necessary to satisfy Swifts strict type system. In the compiled code this is just a cast between pointers. (It can be written shorter as indicated in the *** comments if you are willing to use "unsafe" methods, but the compiled code is identical.)

Using this helper methods you can pass self to a C function as

 let voidPtr = bridge(self)

(or UnsafeMutablePointer<Void>(bridge(self)) if the C function requires a mutable pointer), and convert it back to an object pointer – e.g. in a callback function – as

 let mySelf : MyType = bridge(voidPtr)

No transfer of ownership takes place, so you must ensure that self exists as long as the void pointer is used.


And for the sake of completeness, the Swift equivalent of __bridge_retained and __bridge_transfer from Objective-C would be

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
    return UnsafePointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
    return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeRetainedValue()
}

bridgeRetained() casts the object pointer to a void pointer and retains the object. bridgeTransfer() converts the void pointer back to an object pointer and consumes the retain.

An advantage is that the object cannot be deallocated between the calls because a strong reference is held. The disadvantage is that the calls must be properly balanced, and that it can easily cause retain cycles.


Update for Swift 3 (Xcode 8):

func bridge<T : AnyObject>(obj : T) -> UnsafeRawPointer {
    return UnsafeRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}

func bridge<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
    return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafeRawPointer {
    return UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
    return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}

The relevant changes to "unsafe pointers" are described in

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Sorry for the late reply and thanks for the effort. UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) is the way to pass it. And nice to have those bridge methods to convert the pointer. Thank you. – Peter Peng Oct 26 '15 at 02:27
  • 1
    Thanks!! Wasted so much time on this problem – marchinram Apr 18 '16 at 00:23
  • Can this approach be used like this: 1. Pass in retained `Box` with `weak` variable to `self`. 2. Callback optionally bids the the value to strong. 3. If instance is deallocated and `Box` contains nil the callback consumes the retain of the `Box`? – Kirsteins May 13 '16 at 09:21
  • @Kirsteins: That should be possible but you still have to unregister the callback if the instance is deallocated. It might be easier to pass an unretained pointer and unregister the callback in the `deinit` method of the instance. – Martin R May 16 '16 at 10:23
  • @matt: Thank you. – Martin R Feb 26 '17 at 20:23
4

It seems to me that this is what withUnsafeMutablePointer is for - to convert an arbitrary Swift pointer into a C pointer. So presumably you could do this (I have not tried it, but the code I've tested works safely):

var mself = self 
withUnsafeMutablePointer(&mself) { v in
    let v2 = UnsafeMutablePointer<Void>(v)
    myStruct.inputProcRefCon = v2
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Note that there are going to be memory management issues; "unsafe mutable pointer" means that retaining what's at the far end of the pointer is up to _you_. Therefore I would think that `var mself = self` would need to be replaced by a persistent global. – matt Oct 23 '15 at 15:27
  • 1
    This passes the address of `mself` to the C function, not the address of the object. As you said, `mself` needs to be a global which I find quite inelegant. – The code from http://stackoverflow.com/a/30788165/341994 looks complicated, but actually does *nothing. It just casts the object pointer `self` to a mutable pointer. In fact it can be simplified to `let observer = unsafeAddressOf(self)`, the generated assembly code seems to be identical. – Martin R Oct 23 '15 at 17:44
  • 1
    (Cont.) The advantage of the explicit (complicated) expression is that it matches the reverse conversion from void pointer to object pointer, and that it can be modified to retain the object. – Martin R Oct 23 '15 at 17:47
  • Actually the reverse conversion can be simplified as well using `unsafeBitCast()` ... – Martin R Oct 23 '15 at 18:07
  • Where would you put the `mself` variable? A local variable does not work as you said. A global variable means that two separate instances of the class cannot be registered. An instance variable would lead to a retain cycle. – And how would you recover `self` from the pointer in the callback? I wasn't able to make it work with your approach. – Sorry to keep badgering you, but you reopened the question and asked for my opinion :) Since I cannot close it again, I have now added an answer which summarizes the conversion as I see it. – Martin R Oct 24 '15 at 12:45
  • 2
    @MartinR You're not badgering me. I'm badgering you! My answer was intended to goad you into writing a real explanation, and that's exactly what you did. Thanks! :) – matt Oct 25 '15 at 18:45
2
func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
}


func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer( Unmanaged.passRetained(obj).toOpaque())}

func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()}
Mike
  • 139
  • 1
  • 4
0

This answer doesn't look as topic-specific for a callback as Martin R's answer, but might be of use...

You can typically pass a value of any type to an unsafe void pointer using the & operator:

func baz(p: UnsafeMutablePointer<Void>) -> String {
    return "\(p)"
}

var num = 5
print(baz(&num))

However, to pass self you'll need to do so in a context where self is mutable. That means you'll need to do this in a mutating method (or an init) of a value type, not a reference type:

struct FooValue {
    mutating func bar() {
        print(baz(&self))
    }
}

var myFooValue = FooValue()
myFooValue.bar()

If you want to use a reference type, you'll need to create a local copy of the reference and pass a pointer to that:

class FooReference {
    func bar() {
        var localSelf = self
        print(baz(&localSelf))
    }
}

let myFooReference = FooReference()
myFooReference.bar()
Community
  • 1
  • 1
Nate Cook
  • 92,417
  • 32
  • 217
  • 178