如何在swift中将自我投射到UnsafeMutablePointer <Void>types
在调用下面的代码时,试图快速地将“self”传递给C函数:
var callbackStruct : AURenderCallbackStruct = AURenderCallbackStruct.init( inputProc: recordingCallback, inputProcRefCon: UnsafeMutablePointer<Void> )
在这里将“self”转换为UnsafeMutablePointertypes的理想方式是什么?
一个对象指针(即一个引用types的实例)可以被转换为一个UnsafePointer<Void>
(Swift 3中的const void *
, UnsafeRawPointer
的Swift映射)并返回。 在Objective-C中,你会写
void *voidPtr = (__bridge void*)self; // MyType *mySelf = (__bridge MyType *)voidPtr;
(请参阅Clang ARC文档中的3.2.4桥接模型 ,了解这些模型的准确含义。)
Swift有一个Unmanaged
types的目的。 使用起来有点麻烦,因为它与COpaquePointer
一起使用,而不是UnsafePointer<Void>
。 这里有两个辅助方法(以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) // *** }
“复杂”的expression只是为了满足Swifts严格的types系统。 在编译的代码中,这只是指针之间的转换。 (如果你愿意使用“不安全”的方法,那么它可以写成更短的***
注释,但编译的代码是相同的。)
使用这个帮助器方法,你可以将self
传递给一个C函数
let voidPtr = bridge(self)
(或UnsafeMutablePointer<Void>(bridge(self))
如果C函数需要一个可变指针),并将其转换回对象指针 – 例如在callback函数中 – 作为
let mySelf : MyType = bridge(voidPtr)
不会发生所有权转移,所以只要使用void指针,就必须确保self
存在。
为了完整起见,来自Objective-C的__bridge_retained
和__bridge_transfer
的Swift相当于
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()
将对象指针转换为void指针并保留该对象。 bridgeTransfer()
将void指针转换回对象指针并消耗保留。
一个好处是对象不能在调用之间解除分配,因为强的引用被保留。 缺点是呼叫必须适当平衡,并且容易造成保留周期。
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() }
对“不安全指针”的相关更改在“
- SE-0017更改非托pipe以使用UnsafePointer
- SE-0107 UnsafeRawPointer API
在我看来,这是什么withUnsafeMutablePointer
是 – 将一个任意的Swift指针转换成一个C指针。 所以大概你可以做到这一点(我没有尝试过,但我testing过的代码安全地工作):
var mself = self withUnsafeMutablePointer(&mself) { v in let v2 = UnsafeMutablePointer<Void>(v) myStruct.inputProcRefCon = v2 }
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()}
这个答案不像马丁R的答案看起来像一个callback的主题,但可能是有用的…
您通常可以使用&
运算符将任何types的值传递给不安全的void指针:
func baz(p: UnsafeMutablePointer<Void>) -> String { return "\(p)" } var num = 5 print(baz(&num))
然而,为了通过self
你需要在self
可变的环境中这样做。 这意味着您需要在值types的变异方法(或init
值)中执行此操作,而不是引用types:
struct FooValue { mutating func bar() { print(baz(&self)) } } var myFooValue = FooValue() myFooValue.bar()
如果您想使用引用types,则需要创build引用的本地副本并将指针传递给该引用:
class FooReference { func bar() { var localSelf = self print(baz(&localSelf)) } } let myFooReference = FooReference() myFooReference.bar()