Objective-C Wrapper for CFunctionPointer to a Swift Closure

后端 未结 2 1684
失恋的感觉
失恋的感觉 2020-12-03 15:53

I am playing with Swift and noticed that Swift does not allow to create CFFunctionPointers. It can only pass around and reference existing ones.

As for example Core

相关标签:
2条回答
  • 2020-12-03 16:10

    I needed to define this callback:

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

    and I wanted to use Objective-C as least as possible.

    This was my approach:

    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
    

    Then you can register MIDIReadProcCallback.midiReadProc as callback and set handler MIDIReadProcCallback.setOnCallback({ (packetList: MIDIPacketList) in ... })

    0 讨论(0)
  • 2020-12-03 16:25

    Well, you can create a function pointer.

    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.
    

    It doesn't work though with 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
    

    BTW., you cannot have a bridging header if your MIDI code is in a framework you're writing.

    0 讨论(0)
提交回复
热议问题