un puntatore di oggetto (ossia un'istanza di un tipo riferimento) può essere convertito UnsafePointer<Void>
(mappatura Swift di const void *
, UnsafeRawPointer
in Swift 3) e ritorno. In Objective-C si può scrivere
void *voidPtr = (__bridge void*)self;
//
MyType *mySelf = (__bridge MyType *)voidPtr;
(Cfr 3.2.4 Bridged casts nella documentazione Clang ARC per il preciso significato di queste calchi.)
Swift ha un tipo di Unmanaged
a tale scopo. È un po 'ingombrante da utilizzare perché funziona con COpaquePointer
anziché UnsafePointer<Void>
. Qui ci sono due metodi di supporto (dal nome del __bridge
getto Objective-C):
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) // ***
}
L'espressione "complicata" è solo necessario per conformarsi a Rondoni rigoroso sistema di tipo. Nel codice compilato questo è solo un cast tra i puntatori. (Può essere scritto più breve, come indicato nelle ***
commenti se si è disposti a usare metodi "non sicuri", ma il codice compilato è identica.)
L'utilizzo di questo metodi di supporto è possibile passare self
a una funzione C come
let voidPtr = bridge(self)
(o UnsafeMutablePointer<Void>(bridge(self))
se la funzione C richiede un puntatore mutevole), e convertirlo indietro ad un puntatore oggetto - es in una funzione di callback - come
let mySelf : MyType = bridge(voidPtr)
Nessun trasferimento di proprietà avviene, quindi è necessario assicurarsi che self
esiste fino a quando il puntatore nullo viene utilizzato.
E per amor di completezza, l'equivalente di Swift __bridge_retained
e __bridge_transfer
da Objective-C sarebbe
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()
getta il puntatore all'oggetto a un puntatore nullo e conserva l'oggetto. bridgeTransfer()
converte il puntatore del vuoto di in un puntatore a un oggetto e utilizza il retain.
Un vantaggio è che l'oggetto non può essere deallocato tra le chiamate perché viene mantenuto un riferimento forte. Lo svantaggio è che le chiamate devono essere correttamente bilanciate e che può facilmente causare mantenere cicli .
Aggiornamento per 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()
}
I cambiamenti relativi alla "puntatori non sicuri" sono descritti in
Come si assegna auto a inputProcRefCon? Spero che tu abbia approfondito questo argomento: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html – Shripada
Un altro esempio: http://stackoverflow.com/questions/33260808/swift- corretto uso-di-cfnotificationcenteraddobserver-w-callback/33262376 # 33262376. –
In realtà @MartinR Penso che la tua risposta qui sia più utile: http://stackoverflow.com/a/30788165/341994 – matt