[英]How to cast self to UnsafeMutablePointer<Void> type in swift
Trying to pass "self" to a C function in swift, when calling following code: 调用以下代码时,试图将“ self”快速传递给C函数:
var callbackStruct : AURenderCallbackStruct =
AURenderCallbackStruct.init(
inputProc: recordingCallback,
inputProcRefCon: UnsafeMutablePointer<Void>
)
What is the ideal way to cast "self" to a UnsafeMutablePointer type here? 在这里将“自我”转换为UnsafeMutablePointer类型的理想方法是什么?
An object pointer (ie 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. 可以将对象指针(即引用类型的实例)转换为
UnsafePointer<Void>
(在Swift 3中为const void *
的Swift映射,在UnsafeRawPointer
中是)。 In Objective-C you would write 在Objective-C中,您将编写
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.) (有关这些转换的确切含义,请参见Clang ARC文档中的3.2.4桥接转换。)
Swift has an Unmanaged
type for that purpose. Swift为此具有
Unmanaged
类型。 It is a bit cumbersome to use because it works with COpaquePointer
instead of UnsafePointer<Void>
. 使用它有点麻烦,因为它与
COpaquePointer
而不是UnsafePointer<Void>
。 Here are two helper methods (named after the Objective-C __bridge
cast): 这是两种辅助方法(以Objective-C
__bridge
命名):
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. 仅在满足Swifts严格类型系统时才需要“复杂”表达式。 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 使用此辅助方法,您可以将
self
传递给C函数,如下所示:
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 – eg in a callback function – as (如果C函数需要可变的指针,
UnsafeMutablePointer<Void>(bridge(self))
),然后将其转换回对象指针(例如在回调函数中),如下所示:
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. 不会发生所有权转移,因此,只要使用void指针,就必须确保
self
存在。
And for the sake of completeness, the Swift equivalent of __bridge_retained
and __bridge_transfer
from Objective-C would be 为了完整起见,将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()
casts the object pointer to a void pointer and retains the object. bridgeRetained()
将对象指针强制转换为void指针,并保留对象。 bridgeTransfer()
converts the void pointer back to an object pointer and consumes the retain. bridgeTransfer()
将void指针转换回对象指针并使用保留。
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): 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 有关“不安全指针”的相关更改,请参见
It seems to me that this is what withUnsafeMutablePointer
is for - to convert an arbitrary Swift pointer into a C pointer. 在我看来,这就是
withUnsafeMutablePointer
的用途-将任意Swift指针转换为C指针。 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
}
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()}
This answer doesn't look as topic-specific for a callback as Martin R's answer , but might be of use... 这个答案看起来不像Martin R的答案那样是特定于回调的主题,但可能有用...
You can typically pass a value of any type to an unsafe void pointer using the &
operator: 通常,您可以使用
&
运算符将任何类型的值传递给不安全的void指针:
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. 但是,要传递
self
您需要在self
易变的环境中进行传递。 That means you'll need to do this in a mutating method (or an init
) of a value type, not a reference type: 这意味着您需要使用值类型而不是引用类型的变异方法(或
init
)来执行此操作:
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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.