【问题标题】:How to cast self to UnsafeMutablePointer<Void> type in swift如何快速将自己转换为 UnsafeMutablePointer<Void> 类型
【发布时间】:2026-02-22 10:35:01
【问题描述】:

在调用以下代码时,尝试将“self”快速传递给 C 函数:

var callbackStruct : AURenderCallbackStruct = 
    AURenderCallbackStruct.init(
      inputProc: recordingCallback,
      inputProcRefCon: UnsafeMutablePointer<Void>
    )

在这里将“self”转换为 UnsafeMutablePointer 类型的理想方法是什么?

【问题讨论】:

标签: swift pointers casting unsafe-pointers


【解决方案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()
}

“不安全指针”的相关变化在

中有所描述

【讨论】:

  • 抱歉回复晚了,感谢您的努力。 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()
    

    【讨论】: