如何在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有一个Unmanagedtypes的目的。 使用起来有点麻烦,因为它与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()