27

如果我有这样的方法:

func someMethod(contextPtr: UnsafeMutablePointer<Void>)

如何从 中获取对象contextPtr

func someMethod(contextPtr: UnsafeMutablePointer<Void>){    
    let object:MyObject = contextPtr.memory
}

给出:

'Void' 不能转换为 'MyObject'

秘方是什么


更多详情:

我实际上在这里做的是设置一个全局回调函数SCNetworkReachability

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {

    let r:Reachability = info.memory
}

然后添加回调如下:

var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
var s = self
withUnsafeMutablePointer(&s) {
    context.info = UnsafeMutablePointer($0)
}
SCNetworkReachabilitySetCallback(reachability, callback, &context)
4

2 回答 2

44

这应该有效:将对象指针作为不透明的非托管指针传递给回调:

context.info = UnsafeMutablePointer(Unmanaged.passUnretained(myObject).toOpaque())
SCNetworkReachabilitySetCallback(reachability, callback, &context) 

并通过以下方式在回调中检索:

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {

    let myObject = Unmanaged<MyObject>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()

}

当然,这假设只要安装了回调,就存在对该对象的一些强引用,因此不会释放该对象。

更新:请注意,如果您愿意使用“不安全”函数,则可以简化从对象指针到 void 指针和返回的转换:

context.info = unsafeAddressOf(myObject)
// ...
myObject = unsafeBitCast(info, MyObject.self)

生成的汇编代码——据我所知——是相同的。

更新 2:另请参阅How to cast self to UnsafeMutablePointer<Void> type in swift以获取有关“桥接”和可以在此处使用的一些辅助函数的更多信息。


Swift 3 更新(Xcode 8 beta 6):

var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())

// ...

func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
    if let info = info {
        let myObject = Unmanaged<MyObject>.fromOpaque(info).takeUnretainedValue()
        // ...
    }
}
于 2015-06-11T18:01:05.057 回答
-2
struct S {
    var i: Int = 10
}
var first = S()

func foo(contextPtr: UnsafeMutablePointer<Void>){
    let pS = UnsafeMutablePointer<S>(contextPtr)
    pS.memory.i = 100
}
print(first.i) // 10
foo(&first)
print(first.i) // 100

如果我们需要作为 UnsafeMutablePointer self 传递给异步函数

import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

import Foundation
// can be struct, class ...
class C {
    let queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
    var s: String = ""
    func foo() {
        var c = self
        dispatch_async(queue) { () -> Void in
            f(&c)
        }

    }
}

func f(pV: UnsafeMutablePointer<Void>) {
    let pC = UnsafeMutablePointer<C>(pV)
    sleep(1)
    print(pC.memory.s)
}

var c1: C? = C()
c1!.s = "C1"
c1!.foo()        // C1
var c2: C? = C()
c2!.s = "C2"
c2!.foo()        // C2
c1 = nil
c2 = nil
print("test")
于 2015-11-11T09:50:30.420 回答