开发者问题收集

在 Swift 中传递 C 函数回调

2014-08-16
3146

如何在 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)

        // ...
    }
}
3个回答

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

然后只需像在 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)

        // ...
    }
}

对于您不应该尝试在 Swift 中表达的问题,这是一个非常痛苦的解决方法。必须操作指针(尤其是函数指针)的代码最好留在 C 或 Objective-C 文件中。否则,您只是在与语言进行不必要的斗争 - 尤其是因为它对 C 和 Objective-C 互操作性有如此出色的支持。

CodaFi
2014-10-05

使用 Swift 2.0,现在可以在纯 Swift 中设置回调!请查看 http://oleb.net/blog/2015/06/c-callbacks-in-swift/ Swift 2 无法使用类型的参数列表调用“FSEventStreamCreate” 以获得灵感 :)

Jens Schwarzer
2015-07-24

SWIFT 2 中使用 回调(块) 调用 API 函数

      self.forwardGetRequestToServer(finalUrl!) { (result) -> Void in
        print(result)
    }

在 API 类中返回回调定义的函数

func forwardGetRequestToServer(url: NSURL, completion: (result: NSDictionary) -> Void) {
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "GET"
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in
        if error != nil {
            print("error=\(error)")
            return
        }
        do {

            let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as! NSDictionary
            completion(result: json)

        } catch {
            print("error serializing JSON: \(error)")

        }

        }

    task.resume() }
Maninderjit Singh
2015-12-10