用于CFunctionPointer的Objective-C包装指向Swift闭包



我在玩Swift,注意到Swift不允许创建CFFunctionPointers。它只能传递和引用现有的。

例如,CoreAudio要求CFunctionPointer指向某些回调,因此我不能使用纯Swift。

因此,我需要在这里使用一些Objective-C蹦床或包装器,它以Swift闭包作为参数,以及原始回调原型,然后可以被指定为回调,但实际操作发生在Swift中,而不是Objective-C中。

我该怎么做?

这种包装器的一些示例代码将帮助我理解如何以灵活的方式使用目标C中的Swift代码来实现这些目的,以解决Swift无法创建CFunctionPointer的问题。

是的,我知道我可以在需要的时候在Objective-C中写东西。我想在纯Swift中做这件事,作为将我的一个应用程序移植到Swift的学习练习(使用了很多CoreAudio/CoreVideo框架)。

我需要定义这个回调:

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

我希望尽可能少地使用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注册为回调并设置处理程序MIDIReadProcCallback.setOnCallback({ (packetList: MIDIPacketList) in ... })

好吧,可以创建一个函数指针。

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代码在您正在编写的框架中,则不能有桥接标头。

最新更新