I get this error when I try to change variables in the closure:
A C function pointer cannot be formed from a closure that captures context
Is there a work around or is it possible to still change the variables within the closure?
My Code:
let callback: @convention(c) (readStream: CFWriteStream!, event: CFStreamEventType, data: UnsafeMutablePointer<Void>) -> Void = {
(readStream, event, data) -> Void in
switch event {
case CFStreamEventType.ErrorOccurred:
self.isError = true
break
case CFStreamEventType.EndEncountered:
self.isRunLoop = false
break
case CFStreamEventType.HasBytesAvailable:
break
case CFStreamEventType.OpenCompleted:
break
case CFStreamEventType.CanAcceptBytes:
self.bytesWritten = CFWriteStreamWrite(readStream, self.buffer, self.leftOverSize)
break
default:
break
}
}
let registeredEvents: CFOptionFlags =
CFStreamEventType.CanAcceptBytes.rawValue |
CFStreamEventType.HasBytesAvailable.rawValue |
CFStreamEventType.ErrorOccurred.rawValue |
CFStreamEventType.EndEncountered.rawValue |
CFStreamEventType.None.rawValue
var context = CFStreamClientContext(version: CFIndex(0), info: nil, retain: nil, release: nil, copyDescription: nil)
let stream = CFWriteStreamCreateWithFTPURL(nil, uploadURL).takeUnretainedValue()
CFWriteStreamSetClient(stream, registeredEvents, callback, &context)
I assume you want to use this callback to pass it as the third argument (clientCB
) to CFWriteStreamSetClient.
Due to the fact that that parameter has the following type definition
typedef void (*CFWriteStreamClientCallBack) ( CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo );
you can only use either a global function or a closure that doesn't capture any variables (like self
) from the surrounding context.
What you can do in this case is to pass self
to the info
field of the CFStreamClientContext
structure (the 4th parameter of CFWriteStreamSetClient
), and use that info to reconstruct self
within the closure:
let callback: @convention(c) (readStream: CFWriteStream!, event: CFStreamEventType, data: UnsafeMutablePointer<Void>) -> Void = {
(readStream, event, data) -> Void in
// assuming your class name is Client
let client = unsafeBitCast(data.memory, Client.self)
switch event {
case CFStreamEventType.ErrorOccurred:
client.isError = true
case CFStreamEventType.EndEncountered:
client.isRunLoop = false
case CFStreamEventType.HasBytesAvailable:
break
case CFStreamEventType.OpenCompleted:
break
case CFStreamEventType.CanAcceptBytes:
client.bytesWritten = CFWriteStreamWrite(readStream, client.buffer, client.leftOverSize)
default:
break
}
}
var context = CFStreamClientContext(version: 0, info: unsafeBitCast(self, UnsafeMutablePointer<Void>.self), retain: nil, release: nil, copyDescription: nil)
CFWriteStreamSetClient(stream, 0, callback, &context)
Note. As with Objective-C, you need to make sure self
is not destroyed before the stream is, otherwise you'll likely get into crashes if the stream receives new events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With