objective-c cocoa swift coremidi

objective c - Usando Swift CFunctionPointer para pasar una devolución de llamada a la API de CoreMIDI



objective-c cocoa (2)

Puede ser que esto no sea posible actualmente, lo que sería desafortunado. Intento llamar a la API de CoreMIDI para configurar una entrada MIDI. Esto es lo que trato de hacer en Swift:

var midiClient = MIDIClientRef() var inputPort = MIDIEndpointRef() var status: OSStatus func readProc(packetList: UnsafePointer<MIDIPacketList>, readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void { } status = MIDIClientCreate("MIDI client", nil, nil, &midiClient); status = MIDIDestinationCreate(midiClient, "MIDI input", readProc, nil, &inputPort);

Pero me sale este error: ''(UnsafePointer, UnsafeMutablePointer, UnsafeMutablePointer) -> Void'' no es convertible a ''MIDIReadProc''

MIDIReadProc''s typedef es el siguiente:

typealias MIDIReadProc = CFunctionPointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void>) -> Void)>

¿Hay alguna manera de hacer que un puntero de función para mi método readProc pase a MIDIDestinationCreate API?


En Swift 2.0 (actualmente en versión beta, como parte de la versión beta de Xcode 7), las API de C que se ocupan de los indicadores de función utilizan tipos de funciones anotadas @convention(c) . Puede pasar cualquier función, método o cierre de Swift como un tipo de función @convention(c) , pero solo si ese cierre se ajusta a las convenciones de C ... por ejemplo, no puede capturar el estado de su ámbito circundante.

Para más detalles, vea Atributos de tipo en El lenguaje de programación Swift .

En cuanto a lo que está actualmente fuera de beta ... Swift 1.x no tiene una forma de convertir una función Swift o cierre a un puntero de función C - el único uso del tipo CFunctionPointer es pasar los punteros de función importados desde (Obj ) C API a otras (Obj) C API.

Puede declarar un puntero de función en código C que exponga a Swift a través del encabezado de puente de su proyecto, luego use Swift para pasarlo a CoreMIDI. Pero como de todos modos vas a estar cruzando un puente, podrías pensar qué partes de tu proyecto es mejor mantener en C y cuál es la mejor interfaz entre esas partes y tu código Swift.


Swift 1.x (Old Way)

Hay una forma de hacerlo: Objective-C Runtime es el truco.

import CoreMIDI let block : @objc_block (UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void>) -> Void = { (pktlist,readProcRefCon,srcConnRefCon) in //Your code goes here... } let imp : COpaquePointer = imp_implementationWithBlock(unsafeBitCast(block, AnyObject.self)) let callback : MIDIReadProc = unsafeBitCast(imp, MIDIReadProc.self)

Funciona con devoluciones de llamada de CoreFoundation. Debería funcionar también para CoreMIDI.

Swift 2.x (Nueva forma)

En Swift 2, el proceso se vuelve "menos hacky" (y algo más legible).

import CoreMIDI let callback : @convention(c) (pktlist : UnsafePointer<MIDIPacketList>, readProcRefCon : UnsafeMutablePointer<Void>, srcConnRefCon : UnsafeMutablePointer<Void>) -> Void = { (pktlist, readProcRefCon, srcConRefCon) in } let usableCallback = unsafeBitCast(callback, MIDIReadProc.self)