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