如何快速将自己转换为 UnsafeMutablePointer<Void> 类型
Posted
技术标签:
【中文标题】如何快速将自己转换为 UnsafeMutablePointer<Void> 类型【英文标题】:How to cast self to UnsafeMutablePointer<Void> type in swift 【发布时间】:2015-10-23 03:55:30 【问题描述】:在调用以下代码时,尝试将“self”快速传递给 C 函数:
var callbackStruct : AURenderCallbackStruct =
AURenderCallbackStruct.init(
inputProc: recordingCallback,
inputProcRefCon: UnsafeMutablePointer<Void>
)
在这里将“self”转换为 UnsafeMutablePointer 类型的理想方法是什么?
【问题讨论】:
你如何将 self 分配给 inputProcRefCon?希望你经历过这个-developer.apple.com/library/ios/documentation/Swift/Conceptual/… 另一个例子:***.com/questions/33260808/…. 其实@MartinR 我认为你在这里的回答更有帮助:***.com/a/30788165/341994 @matt:但这正是我用作“重复”的线程。我在评论中添加了另一个链接,因为它显示了一个完整的独立示例,即使问题不同。 – 也许我没明白你的意思? 知道了。干杯,伙计们。 【参考方案1】:一个对象指针(即一个引用类型的实例)可以是
转换为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 Bridged casts 了解这些的确切含义 演员表。)
为此,Swift 有一个 Unmanaged
类型。
使用起来有点麻烦,因为它适用于COpaquePointer
而不是UnsafePointer<Void>
。这里有两个辅助方法
(以 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) // ***
“复杂”的表达式只需要满足 Swifts
严格的类型系统。在编译后的代码中,这只是一个演员表
指针之间。 (它可以写得更短,如***
cmets 所示
如果您愿意使用“不安全”的方法,但编译
代码相同。)
使用这个辅助方法,您可以将 self
传递给 C 函数
let voidPtr = bridge(self)
(或 UnsafeMutablePointer<Void>(bridge(self))
如果 C 函数需要
可变指针),并将其转换回对象指针——例如
在回调函数中 - as
let mySelf : MyType = bridge(voidPtr)
不会发生所有权转移,因此您必须确保self
只要使用 void 指针就存在。
为了完整起见,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 Change Unmanaged to use UnsafePointer SE-0107 UnsafeRawPointer API【讨论】:
抱歉回复晚了,感谢您的努力。 UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) 是通过它的方式。很高兴有这些桥接方法来转换指针。谢谢。 谢谢!!在这个问题上浪费了这么多时间 这种方法可以这样使用吗: 1. 将保留的Box
和weak
变量传递给self
。 2. 回调可选地将该值出价至强。 3. 如果实例被释放并且Box
包含nil,则回调会消耗Box
的保留?
@Kirsteins:这应该是可能的,但如果实例被释放,您仍然必须取消注册回调。在实例的deinit
方法中传递未保留的指针并取消注册回调可能更容易。
@matt:谢谢。【参考方案2】:
在我看来,这就是withUnsafeMutablePointer
的用途——将任意 Swift 指针转换为 C 指针。所以大概你可以这样做(我没有尝试过,但我测试过的代码可以安全运行):
var mself = self
withUnsafeMutablePointer(&mself) v in
let v2 = UnsafeMutablePointer<Void>(v)
myStruct.inputProcRefCon = v2
【讨论】:
注意会有内存管理问题; “不安全的可变指针”意味着保留指针远端的内容取决于您。因此我认为var mself = self
需要被一个持久的全局替换。
这会将mself
的地址传递给C 函数,而不是对象的地址。正如您所说,mself
必须是一个全局变量,我觉得这很不优雅。 – ***.com/a/30788165/341994 中的代码看起来很复杂,但实际上*什么都不做。它只是将对象指针self
转换为可变指针。其实可以简化为let observer = unsafeAddressOf(self)
,生成的汇编代码好像是一样的。
(续)显式(复杂)表达式的优点是它匹配了从void指针到对象指针的反向转换,并且可以修改它以保留对象。
其实反向转换也可以使用unsafeBitCast()
...
@MartinR 你不是在纠缠我。我在纠缠你!我的回答旨在促使你写一个真正的解释,而这正是你所做的。谢谢! :)【参考方案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()
【讨论】:
【参考方案4】:这个答案看起来不像 Martin R's answer 这样的回调特定主题,但可能有用...
您通常可以使用 &
运算符将任何类型的值传递给不安全的 void 指针:
func baz(p: UnsafeMutablePointer<Void>) -> String
return "\(p)"
var num = 5
print(baz(&num))
但是,要传递self
,您需要在self
是可变的上下文中这样做。这意味着您需要在值类型的变异方法(或init
)中执行此操作,而不是引用类型:
struct FooValue
mutating func bar()
print(baz(&self))
var myFooValue = FooValue()
myFooValue.bar()
如果你想使用一个引用类型,你需要创建一个引用的本地副本并传递一个指向它的指针:
class FooReference
func bar()
var localSelf = self
print(baz(&localSelf))
let myFooReference = FooReference()
myFooReference.bar()
【讨论】:
以上是关于如何快速将自己转换为 UnsafeMutablePointer<Void> 类型的主要内容,如果未能解决你的问题,请参考以下文章