2015-06-11 15 views
20

Se ho un metodo come:Swift 2 - UnsafeMutablePointer <Void> di opporsi

func someMethod(contextPtr: UnsafeMutablePointer<Void>) 

Come faccio a ottenere l'oggetto dalla contextPtr?

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

dà:

'Vuoto' non è convertibile in 'MyObject'

Qual è il segreto salsa


Più particolare:

W cappello In realtà sto facendo qui è la creazione di una funzione di callback globale per SCNetworkReachability:

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

    let r:Reachability = info.memory 
} 

e quindi aggiungendo il callback come segue:

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) 
+0

Cosa si passa quando tu * chiami * il metodo? E perché è passato come puntatore vuoto? –

+0

Stavo cercando di semplificare un po 'il codice - Ho aggiunto qualche altro dettaglio –

risposta

38

Questo dovrebbe funzionare: passare il puntatore oggetto come un opaco non gestito puntatore al callback:

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

e recuperare nella richiamata tramite:

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

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

} 

Naturalmente questo presuppone che alcuni forti riferimento all'oggetto esiste finché è installata la richiamata, in modo che l'oggetto non è deallocato.

Aggiornamento: notare che sia le conversioni da puntatore oggetto revocatorie puntatore e ritorno possono essere semplificate se si è disposti a utilizzare le funzioni "non sicure":

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

Il codice assembly generato è - per quanto come posso vedere - identico.

Aggiornamento 2: Vedi anche How to cast self to UnsafeMutablePointer<Void> type in swift per ulteriori informazioni sul "ponte" e alcune funzioni di supporto che possono essere utilizzati qui.


Swift 3 aggiornamento (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() 
     // ... 
    } 
} 
+0

Perfetto, grazie. –

+0

@AshleyMills: bello vedere che potresti usarlo nel tuo progetto Reachability! –

+0

Questa era la chiave finale del puzzle! –

-1
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 

se abbiamo bisogno di passare sé come UnsafeMutablePointer a ASYNC funzione

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") 
+2

Tuttavia, il codice di esempio è diverso dalla domanda, poiché 'C.foo()' chiama 'f()' in modo sincrono, quindi 'c' rimane allocato. Nella domanda originale, 'f()' è una funzione di callback asincrona, e quindi 'c' verrebbe rilasciato prima che venga chiamato' f() '. – Dov

Problemi correlati