Обёртка Objective C для CFunctionPointer для быстрого закрытия

Я играю со Swift и заметил, что Swift не позволяет создавать CFFunctionPointers. Он может только обойти и сослаться на существующие.

Как, например, CoreAudio требует CFunctionPointer для определенных обратных вызовов, поэтому я не могу использовать чистый Swift.

Поэтому мне нужно использовать некоторый батут или оболочку Objective-C, который принимает закрытие Swift в качестве параметра, а также прототип обратного вызова, а затем может быть назначен как обратный вызов, но на самом деле действие происходит в Swift, а не в Objective-C,

Как мне это сделать?

Некоторые примеры кода для такой обертки помогут мне понять, как я могу использовать код Swift из цели C для таких целей, гибко обходя Swift, не имея возможности создавать CFunctionPointers.

Да, я знаю, что могу просто писать вещи, когда это необходимо в Objective-C. Я хочу сделать это на чистом Swift в качестве учебного упражнения, портирующего одно из моих приложений на Swift (использует много инфраструктуры CoreAudio /CoreVideo).

2 ответа

Решение

Мне нужно было определить этот обратный вызов:

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-код находится в среде, которую вы пишете.

Другие вопросы по тегам