Swift 2 – UnsafeMutablePointer para object

Se eu tiver um método como:

func someMethod(contextPtr: UnsafeMutablePointer) 

Como obtenho o object do contextPtr ?

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

dá:

‘Void’ não é conversível para ‘MyObject’

Qual é o molho secreto


Mais detalhes:

O que estou realmente fazendo aqui é configurar uma function de retorno de chamada global para o SCNetworkReachability :

 func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer) { let r:Reachability = info.memory } 

e, em seguida, adicionando o retorno de chamada da seguinte maneira:

 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) 

Isso deve funcionar: passe o ponteiro do object como um ponteiro não gerenciado opaco para o retorno de chamada:

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

e recuperar no retorno de chamada via:

 func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer) { let myObject = Unmanaged.fromOpaque(COpaquePointer(info)).takeUnretainedValue() } 

Claro que isso pressupõe que alguma referência forte ao object existe desde que o retorno de chamada seja instalado, para que o object não seja desalocado.

Atualização: Observe que ambas as conversões do ponteiro do object para o ponteiro e para o retorno nulos podem ser simplificadas se você estiver disposto a usar funções “inseguras”:

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

O código de assembly gerado é – até onde eu posso ver – idêntico.

Atualização 2: Veja também Como converter para o tipo UnsafeMutablePointer no swift para mais informações sobre o “bridging” e algumas funções auxiliares que podem ser usadas aqui.


Atualização do 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.fromOpaque(info).takeUnretainedValue() // ... } } 
 struct S { var i: Int = 10 } var first = S() func foo(contextPtr: UnsafeMutablePointer){ let pS = UnsafeMutablePointer(contextPtr) pS.memory.i = 100 } print(first.i) // 10 foo(&first) print(first.i) // 100 

se precisarmos passar como UnsafeMutablePointer self para a function assíncrona

 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) { let pC = UnsafeMutablePointer(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")