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

Implementing a c function callback in Swift 2.0?

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 有一种方法可以将 Swift 闭包与 C 函数回调一起使用,但我似乎无法让它工作。有谁知道在这种情况下该怎么做?

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

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

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

Swift 2.0:

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

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

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

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

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

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()

甚至可以使用任何闭包作为回调:

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