在Swift 2.0中实现c函数回调?

时间:2015-07-02 02:22:13

标签: ios c swift callback swift2

CFReadStreamSetClient在其初始化程序中有一个C函数回调函数(CFReadStreamClientCallBack),

CFReadStreamClientCallback看起来像这样:

typealias CFReadStreamClientCallBack = (CFReadStream!,
        CFStreamEventType, UnsafeMutablePointer<Void>) -> Void

我有一个尝试处理CFReadStreamClientCallBack C函数回调的方法:

func callback(stream: CFReadStreamRef,
        eventType: CFStreamEventType,
        inClientInfo: UnsafeMutablePointer<Void>) {
    }

但是当我尝试按如下方式在CFReadStreamCallback中设置回调时,它不会编译。

CFReadStreamSetClient(stream, registeredEvents, callback, clientContextPtr)

我知道使用Swift 2.0有一种方法可以使用带有C函数回调的Swift闭包,但我似乎无法让它工作。有谁知道在这种情况下如何做到这一点?

2 个答案:

答案 0 :(得分:4)

你可以创建一个闭包来完成你在函数中所做的事情:

CFReadStreamSetClient(stream, registeredEvents, { readStream, event, data -> Void in 
    // Do stuff here.
}, clientContextPtr)

另请注意,C功能块不具备上下文,因此您无法访问自身或来自块外部的任何其他变量。 如果这不起作用,您可以在问题中包含编译器错误吗?

答案 1 :(得分:3)

Swift 2.0:

给定一个带函数指针和上下文的函数:

void c_func_with_callback(void *context, void (*callback)(void *context))

从Swift中调用它很容易,但它无法访问封闭类的变量:

c_func_with_callback(nil) { context in
    print("Callback in Swift!") // OK
    self.xxx // error
}

如果您需要访问块之外的变量,可以使用上下文存储指向该类的指针:

class MyClass {
    func hello() {
        print("MyClass.hello()")
    }

    func classMethodAsCallback() {
        let context = unsafeBitCast(self, UnsafeMutablePointer<Void>.self)
        c_func_with_callback(context) { context in
            let caller = unsafeBitCast(context, MyClass.self)
            caller.hello()
        }
    }
}
let myClass = MyClass()
myClass.classMethodAsCallback()

甚至可以将ANY闭包用作回调:

class MyClass {
    typealias Closure = ()->()

    func anySwiftClosureAsCallback(closure: Closure) {
        var c = closure
        // closure won't fit in a pointer, so take it's address first
        let context = withUnsafePointer(&c) {
                //(ptr: UnsafePointer<Closure>) -> UnsafeMutablePointer<Void> in
                ptr in
            return unsafeBitCast(ptr, UnsafeMutablePointer<Void>.self)
        }
        c_func_with_callback(context) { context in
            let ptr = unsafeBitCast(context, UnsafePointer<Closure>.self)
            let closure = ptr.memory // dereference the address
            closure()
        }
    }
}
let myClass = MyClass()
myClass.anySwiftClosureAsCallback {
    print("Swift closure called")
}