Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C Wrapper for CFunctionPointer to a Swift Closure

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 CoreAudio requires CFunctionPointer to certain callbacks therefore I cannot use pure Swift.

So I need to use some Objective-C trampoline or wrapper here that takes a Swift Closure as a parameter as well as the original callback prototype and then can be assigned to be the callback, but the actually action happens in Swift and not Objective-C.

How do I do this?

Some example code for such a wrapper would help me to understand how I can use Swift code from objective C for such purposes in a flexible way to work around Swift not being able to create CFunctionPointers.

Yes, I know I can just write stuff when needed in Objective-C. I want to do it in pure Swift as a learning exercise porting one of my apps to Swift (uses a lot of CoreAudio/CoreVideo framework).

like image 360
scythe42 Avatar asked Oct 01 '14 09:10

scythe42


1 Answers

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

like image 114
Kirsteins Avatar answered Nov 09 '22 16:11

Kirsteins