关闭捕获上下文Swift

时间:2016-02-11 18:13:35

标签: swift callback closures

当我尝试更改闭包中的变量时,我收到此错误:

A C function pointer cannot be formed from a closure that captures context

是否有解决办法或是否仍然可以更改闭包内的变量?

我的代码:

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)

1 个答案:

答案 0 :(得分:5)

我假设您要使用此回调将其作为第三个参数(clientCB)传递给CFWriteStreamSetClient

由于该参数具有以下类型定义

typedef void (*CFWriteStreamClientCallBack) ( CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo );

你只能使用全局函数或不能从周围上下文中捕获任何变量(如self)的闭包。

在这种情况下,您可以执行的操作是将self传递给info结构的CFStreamClientContext字段(CFWriteStreamSetClient的第4个参数),然后使用在封闭中重建self的信息:

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)

请注意。与Objective-C一样,您需要确保在流之前不会销毁self,否则如果流接收到新事件,您可能会遇到崩溃。