用于CFunctionPointer到快速关闭的Objective-C包装器

时间:2014-10-01 09:54:27

标签: ios pointers swift callback wrapper

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

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

所以我需要在这里使用一些Objective-C trampoline或wrapper,它将Swift Closure作为参数以及原始回调原型然后可以被指定为回调,但实际操作发生在Swift而不是Objective-C的。

我该怎么做?

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

是的,我知道我可以在Objective-C中根据需要编写内容。我想用纯Swift作为学习练习将我的一个应用程序移植到Swift(使用大量的CoreAudio / CoreVideo框架)。

2 个答案:

答案 0 :(得分:8)

我需要定义这个回调:

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 ... })

答案 1 :(得分:-1)

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

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代码在你正在编写的框架中,你就不能有一个桥接标题。