CFReadStreamSetClient has a C-function callback (CFReadStreamClientCallBack) in it's initializer,
CFReadStreamClientCallback looks like this:
typealias CFReadStreamClientCallBack = (CFReadStream!,
CFStreamEventType, UnsafeMutablePointer<Void>) -> Void
I have a method that attempts to handle the CFReadStreamClientCallBack C-function callback:
func callback(stream: CFReadStreamRef,
eventType: CFStreamEventType,
inClientInfo: UnsafeMutablePointer<Void>) {
}
but when i attempt to set the callback in CFReadStreamCallback as follows, it doesn't compile.
CFReadStreamSetClient(stream, registeredEvents, callback, clientContextPtr)
I know with Swift 2.0 there's a way to use Swift closures with C-Function callbacks but I cant seem to get it to work. Does anyone know how it can be done in this situation?
2 Answers 2
You can make a closure that does what you do in the function like this:
CFReadStreamSetClient(stream, registeredEvents, { readStream, event, data -> Void in
// Do stuff here.
}, clientContextPtr)
Also note that C function blocks can't have a context so you can't access self, or any other variable from outside the block. If that doesn't work can you include the compiler error in your question?
2 Comments
AURenderCallbackStruct( inputProc: , inputProcRefCon: &selfPtr )unsafeAddressOf(self) and that that bit is working. Other than that you need this: AURenderCallbackStruct(inputProc: { inRefCon, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData -> OSStatus in // TODO: Stuff that returns an OSStatus }, inputProcRefCon: &selfPtr)Swift 2.0:
Given a function which takes a function pointer and a context:
void c_func_with_callback(void *context, void (*callback)(void *context))
It's very easy to call it from Swift, but it won't be possible to access the variables of the enclosing class:
c_func_with_callback(nil) { context in
print("Callback in Swift!") // OK
self.xxx // error
}
If you need to access variables outside of the block, it's possible to use the context to store a pointer to the 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()
It's even possible to use ANY closure as a callback:
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")
}