如何在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)
// ...
}
}
答案 0 :(得分: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);
}
然后就像你在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的互操作性有很大的支持。
答案 1 :(得分:3)
使用Swift 2.0,现在可以在纯Swift中设置回调!请查看http://oleb.net/blog/2015/06/c-callbacks-in-swift/和Swift 2 Cannot invoke 'FSEventStreamCreate' with an argument list of type获取灵感:)
答案 2 :(得分:-1)
使用 SWIFT 2
中的 回调(阻止) 调用API函数 self.forwardGetRequestToServer(finalUrl!) { (result) -> Void in
print(result)
}
在API类中返回CallBack定义的函数
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() }