这可能是目前实际上不可能的,这是不幸的。我正在尝试调用CoreMIDI API来设置MIDI输入。这就是我想在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);
但我收到此错误:'(UnsafePointer,UnsafeMutablePointer,UnsafeMutablePointer) - &gt; Void'不能转换为'MIDIReadProc'
MIDIReadProc的typedef如下:
typealias MIDIReadProc = CFunctionPointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void>) -> Void)>
有没有办法让我的readProc方法的函数指针传递给MIDIDestinationCreate API?
答案 0 :(得分:25)
在Swift 2.0中(作为Xcode 7的一部分),处理函数指针的C API使用带注释@convention(c)
的函数类型。您可以将任何Swift函数,方法或闭包作为@convention(c)
函数类型传递 - 但前提是该闭包符合C约定...例如它不能从周围的范围中捕获状态。
有关详细信息,请参阅 Swift编程语言中的Type Attributes。
至于Xcode 6中的内容:Swift 1.x没有办法将Swift函数或闭包转换为C函数指针 - CFunctionPointer
类型的唯一用途是传递函数指针从(Obj)C API导入到其他(Obj)C API。
您可以在C代码中声明一个函数指针,通过项目的桥接头向Swift公开,然后使用Swift将其传递给CoreMIDI。但是,无论如何你都要跨越一座桥,你可能会考虑项目的哪些部分最好保留在C中,以及从这些部分到Swift代码的最佳界面是什么。
答案 1 :(得分:18)
Swift 1.x(Old Way)
有一种方法可以做到这一点 - Objective-C Runtime就是一招。
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)
使用CoreFoundation回调。 也应该为CoreMIDI工作。
Swift 2.x(新方式)
在Swift 2中,这个过程变得“不那么hacky”(并且稍微更具可读性)。
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)