How to cast self to UnsafeMutablePointer<Void> type in swift
Solution 1
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
Solution 2
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
}
Solution 3
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()}
Comments
-
Peter Peng about 4 years
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?
-
matt over 8 yearsNote 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. -
Martin R over 8 yearsThis 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 stackoverflow.com/a/30788165/341994 looks complicated, but actually does *nothing. It just casts the object pointerself
to a mutable pointer. In fact it can be simplified tolet observer = unsafeAddressOf(self)
, the generated assembly code seems to be identical. -
Martin R over 8 years(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 over 8 yearsActually the reverse conversion can be simplified as well using
unsafeBitCast()
... -
Martin R over 8 yearsWhere 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 recoverself
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. -
matt over 8 years@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! :)
-
Peter Peng over 8 yearsSorry 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.
-
marchinram about 8 yearsThanks!! Wasted so much time on this problem
-
Kirsteins almost 8 yearsCan this approach be used like this: 1. Pass in retained
Box
withweak
variable toself
. 2. Callback optionally bids the the value to strong. 3. If instance is deallocated andBox
contains nil the callback consumes the retain of theBox
? -
Martin R almost 8 years@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 about 7 years@matt: Thank you.