用于CFunctionPointer的Objective-C包装到Swift Closure

我在玩Swift,注意到Swift不允许创buildCFFunctionPointers。 它只能通过和参考现有的。

例如CoreAudio需要CFunctionPointer来确定callback,因此我不能使用纯Swift。

所以我需要使用一些Objective-C的蹦床或包装,这需要一个Swift Closure作为参数,以及原始的callback原型,然后可以被指定为callback,但实际的行动发生在Swift而不是Objective-C 。

我该怎么做呢?

这样的包装的一些示例代码将帮助我了解如何从目标C中使用Swift代码用于这种目的以灵活的方式解决Swift无法创buildCFunctionPointers。

是的,我知道我只需要在Objective-C中写需要的东西。 我想在纯Swift中做一个学习练习,将我的一个应用程序移植到Swift(使用大量的CoreAudio / CoreVideo框架)。

我需要定义这个callback:

typedef void (*MIDIReadProc) ( const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon ); 

我想尽可能less使用Objective-C。

这是我的方法:

MIDIReadProcCallback.h

 #import <Foundation/Foundation.h> #import <AudioToolbox/AudioToolbox.h> typedef void (^OnCallback)(const MIDIPacketList *packetList); @interface MIDIReadProcCallback : NSObject + (void (*)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon))midiReadProc; + (void)setOnCallback:(OnCallback)onCallback; @end 

MIDIReadProcCallback.m

 #import "MIDIReadProcCallback.h" static OnCallback _onCallback = nil; static void readProcCallback(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) { if (_onCallback) { _onCallback(pktlist); } } @implementation MIDIReadProcCallback + (void (*)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon))midiReadProc { return readProcCallback; } + (void)setOnCallback:(OnCallback)onCallback { _onCallback = onCallback; } @end 

然后,您可以注册MIDIReadProcCallback.midiReadProc作为callback,并设置处理程序MIDIReadProcCallback.setOnCallback({ (packetList: MIDIPacketList) in ... })

那么你可以创build一个函数指针。

 var ump = UnsafeMutablePointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void> ) -> Void)>.alloc(1) ump.initialize(MyMIDIReadProc) let cp = COpaquePointer(ump) let fp = CFunctionPointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void> ) -> Void)>(cp) status = MIDIDestinationCreate(midiClient, name, fp, etc. 

它与Core MIDI不起作用。

 thread #7: tid = 0x713b7, 0x7a1541f0, stop reason = EXC_BAD_ACCESS (code=2, address=0x7a1541f0) frame #0: 0x7a1541f0 frame #1: 0x00159295 CoreMIDI`LocalMIDIReceiverList::HandleMIDIIn(void*, OpaqueMIDIEndpoint*, void*, MIDIPacketList const*) + 117 

顺便说一句,如果你的MIDI代码是在你正在编写的框架中,你就不能有桥接头。