2015-06-11 6 views
20

Wenn ich eine Methode, wie haben:Swift 2 - UnsafeMutablePointer <Void> zum Objekt

func someMethod(contextPtr: UnsafeMutablePointer<Void>) 

wie bekomme ich das Objekt aus dem contextPtr?

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

gibt:

'Void' ist nicht konvertierbar 'MyObject'

Was ist das Geheimnis Sauce ist


Mehr Detail:

W

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

    let r:Reachability = info.memory 
} 

und dann den Rückruf Zugabe wie folgt:: Ich Hut bin eigentlich hier tun, ist eine globale Callback-Funktion für SCNetworkReachability Einrichtung

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

Was passieren Sie, wenn du * rufst * die Methode an? Und warum wird es als ungültiger Zeiger übergeben? –

+0

Ich habe versucht, den Code ein wenig zu vereinfachen - ich habe einige weitere Details hinzugefügt –

Antwort

38

Diese Arbeit sollte: den Objektzeiger als opake passieren nicht verwalteten Zeiger auf den Rückruf:

:

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

und über in den Rückruf abrufen

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

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

} 

Natürlich setzt dies voraus, dass einige starke Referenz auf das Objekt existiert solange der Rückruf installiert ist, so dass das Objekt nicht deallokierten ist.

Update: Beachten Sie, dass beide Konvertierungen von Objekt Zeiger auf void Zeiger und zurück vereinfacht werden können, wenn Sie bereit sind, „unsicher“ Funktionen zu verwenden:

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

Der erzeugte Assembler-Code ist - so weit wie ich sehen kann - identisch.

Update 2: Siehe auch How to cast self to UnsafeMutablePointer<Void> type in swift für weitere Informationen über die „Überbrückung“ und einige Hilfsfunktionen, die hier verwendet werden können.


Swift 3-Update (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

Perfekt, danke. –

+0

@AshleyMills: Schön zu sehen, dass Sie es in Ihrem Erreichbarkeitsprojekt verwenden könnten! –

+0

Das war der letzte Schlüssel zum 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 

wenn wir als UnsafeMutablePointer selbst brauchen passieren Funktion Asynchron

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

Ihr Beispielcode unterscheidet sich jedoch von der Frage, weil 'C.foo()' 'f()' synchron aufruft, also bleibt 'c' reserviert. In der ursprünglichen Frage ist 'f()' eine asynchrone Callback-Funktion, und so würde 'c' freigegeben, bevor' f() 'aufgerufen wird. – Dov

Verwandte Themen