swift pointers casting unsafe-pointers

Cómo lanzarse al tipo UnsafeMutablePointer<Void> en swift



pointers casting (4)

Intentando pasar "self" a una función C de forma rápida, al llamar al siguiente código:

var callbackStruct : AURenderCallbackStruct = AURenderCallbackStruct.init( inputProc: recordingCallback, inputProcRefCon: UnsafeMutablePointer<Void> )

¿Cuál es la forma ideal de emitir "self" a un tipo UnsafeMutablePointer aquí?


Me parece que para eso es con withUnsafeMutablePointer : para convertir un puntero Swift arbitrario en un puntero C. Entonces, presumiblemente, podría hacer esto (no lo he probado, pero el código que he probado funciona de manera segura):

var mself = self withUnsafeMutablePointer(&mself) { v in let v2 = UnsafeMutablePointer<Void>(v) myStruct.inputProcRefCon = v2 }


Un puntero de objeto (es decir, una instancia de un tipo de referencia ) puede convertirse en un UnsafePointer<Void> (el mapeo Swift de const void * , UnsafeRawPointer en Swift 3) y viceversa. En Objective-C escribirías

void *voidPtr = (__bridge void*)self; // MyType *mySelf = (__bridge MyType *)voidPtr;

(Ver 3.2.4 Moldes en puente en la documentación de Clang ARC para el significado exacto de estos moldes).

Swift tiene un tipo no Unmanaged para ese propósito. Es un poco engorroso de usar porque funciona con COpaquePointer lugar de UnsafePointer<Void> . Aquí hay dos métodos auxiliares (nombrados después del reparto de Objective-C __bridge ):

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) // *** }

La expresión "complicada" solo es necesaria para satisfacer el sistema de tipo estricto de Swifts. En el código compilado, esto es solo un reparto entre punteros. (Se puede escribir más corto como se indica en los comentarios *** si está dispuesto a utilizar métodos "inseguros", pero el código compilado es idéntico).

Usando estos métodos de ayuda puede pasar a una función C como

let voidPtr = bridge(self)

(o UnsafeMutablePointer<Void>(bridge(self)) si la función C requiere un puntero mutable) y conviértalo de nuevo a un puntero de objeto, por ejemplo, en una función de devolución de llamada, como

let mySelf : MyType = bridge(voidPtr)

No se realiza ninguna transferencia de propiedad, por lo que debe asegurarse de que existe self mismo siempre que se utilice el puntero nulo.

Y en aras de la exhaustividad, el equivalente rápido de __bridge_retained y __bridge_transfer de Objective-C sería

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() el puntero del objeto en un puntero vacío y retiene el objeto. bridgeTransfer() convierte el puntero vacío de nuevo en un puntero de objeto y consume la retención.

Una ventaja es que el objeto no se puede desasignar entre las llamadas porque se mantiene una referencia fuerte. La desventaja es que las llamadas deben estar correctamente equilibradas, y que puede causar fácilmente ciclos de retención.

Actualización para 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() }

Los cambios relevantes a los "punteros inseguros" se describen en


Esta respuesta no parece tan específica del tema para una devolución de llamada como la respuesta de Martin R , pero podría ser útil ...

Por lo general, puede pasar un valor de cualquier tipo a un puntero vacío inseguro utilizando el operador & :

func baz(p: UnsafeMutablePointer<Void>) -> String { return "/(p)" } var num = 5 print(baz(&num))

Sin embargo, para aprobar el self , deberá hacerlo en un contexto en el que el self sea ​​mutable. Eso significa que tendrá que hacer esto en un método de mutación (o un init ) de un tipo de valor, no un tipo de referencia:

struct FooValue { mutating func bar() { print(baz(&self)) } } var myFooValue = FooValue() myFooValue.bar()

Si desea utilizar un tipo de referencia, deberá crear una copia local de la referencia y pasar un puntero a eso:

class FooReference { func bar() { var localSelf = self print(baz(&localSelf)) } } let myFooReference = FooReference() myFooReference.bar()


func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> { return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque()) } func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T { return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue() } 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(ptr).takeRetainedValue()}