使用Swift CFunctionPointer将回调传递给CoreMIDI API

时间:2014-08-26 19:56:01

标签: objective-c cocoa swift coremidi

这可能是目前实际上不可能的,这是不幸的。我正在尝试调用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?

2 个答案:

答案 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)