在Swift中传递C函数回调

Eri*_*ner 9 swift

你如何在Swift中传递C回调?考虑这个例子:

class AudioQueue {

    var desc : AudioStreamBasicDescription
    var queue : AudioQueue?

    func audioQueueHandleBuffer(ctx : UnsafeMutablePointer<()>,
                                inAQ : AudioQueue!,
                                inBuffer : AudioQueueBufferRef) {
       // do stuff
    }

    func initialize() {
        // this does not work!
        var err = AudioQueueNewOutput(&desc, audioQueueHandleBuffer,
                                      nil, nil, nil, 0, queue)

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*aFi 8

Swift闭包和函数绝对不是C函数.它们存在于C++成员和Objective-C块之间的奇怪的中间状态,因此您必须将任何回调移动到Objective-C文件中并采取阻塞或使用其他方法回调Swift.例如,您可能有自己版本的相关AVFoundation函数占用块:

void audioQueueHandleBuffer(void *ctx, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
    NSCAssert(ctx != NULL, @"Cannot execute NULL context block.");

    void(^block)(AudioQueueRef, AudioQueueBufferRef) = (__bridge void(^)(AudioQueueRef, AudioQueueBufferRef))ctx;

    return block(inAQ, inBuffer);
}

OSStatus CFIAudioQueueNewOutput(AudioStreamBasicDescription *desc, void(^callback)(AudioQueueRef, AudioQueueBufferRef), AudioQueueRef *queue) {
    return AudioQueueNewOutput(desc, audioQueueHandleBuffer, (__bridge_retained void *)([callback copy]), nil, nil, 0, queue);
}
Run Code Online (Sandbox Code Playgroud)

然后就像你在Swift中所期望的那样传递你的函数.

class AudioQueue {

    var desc : AudioStreamBasicDescription
    var queue : AudioQueueRef

    func audioQueueHandleBuffer(inAQ : AudioQueueRef, inBuffer : AudioQueueBufferRef) {
            // do stuff
    }

    func initialize() {
        var err = CFIAudioQueueNewOutput(&desc, audioQueueHandleBuffer, &queue)

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

对于一个你不应该试图在Swift中表达的问题,这是一个令人难以置信的痛苦的解决方法.必须操作指针的代码,尤其是函数指针,最好留在C或Objective-C文件中.否则,你只是在与语言进行不必要的斗争 - 特别是因为它对C和Objective-C互操作性有如此强大的支持.


Jen*_*zer 2

使用 Swift 2.0,现在可以在纯 Swift 中设置回调!请检查http://oleb.net/blog/2015/06/c-callbacks-in-swift/Swift 2 Cannot invoke 'FSEventStreamCreate' with a argument list of type以获得灵感:)