如何快速将自己转换为 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&lt;Void&gt;(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&lt;Void&gt;。这里有两个辅助方法 (以 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&lt;Void&gt;(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. 将保留的Boxweak 变量传递给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 这样的回调特定主题,但可能有用...

您通常可以使用 &amp; 运算符将任何类型的值传递给不安全的 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> 类型的主要内容,如果未能解决你的问题,请参考以下文章

如何快速将自己转换为 UnsafeMutablePointer<Void> 类型

如何快速将MOV格式视频转换成MP4格式

教你如何快速将cad转jpg格式?

如何快速将 byte[] 转换为字符串?

如何快速将 PFFile 转换为 UIImage?

如何修复错误无法将 [NSDictionary] 快速转换为 NSDictionary?