Swift 3 中的未来实施

Future implementation in Swift 3

我正在尝试使用 Swift 3 实现一个小型的未来(承诺)库,灵感来自 this talk 这是我的实现:

public enum Result<T, E: Error> {
    case Success(T)
    case Error(E)
}

public struct Future<T, E: Error> {
    public typealias ResultType = Result<T, E>
    public typealias Completion = (ResultType) -> Void
    public typealias AsyncOperation = (Completion) -> Void

    private let operation: AsyncOperation

    public init(result: ResultType) {
        self.init(operation: { completion in
            completion(result)
        })
    }

    public init(value: T) {
        self.init(result: .Success(value))
    }

    public init(error: E) {
        self.init(result: .Error(error))
    }
    public init(operation: @escaping (Completion) -> Void) {
        self.operation = operation
    }

    public func start(completion: Completion) {
        self.operation() { result in
            completion(result)
        }
    }
}

//: ### Error handeling

enum UserInfoErrorDomain: Error {
    case UserDoesNotExist
    case UserRequestFailure
    case NetworkRequestFailure
}

这是我的用法:

func downloadFile(URL: NSURL) -> Future<NSData, UserInfoErrorDomain> {

    return Future(operation: { completion in
            DispatchQueue.main.async( execute: {
                print("Async2")
                let result: Result<NSData, UserInfoErrorDomain>

                if let data = NSData(contentsOf: URL as URL) {
                    result = Result.Success(data)
                }
                else {
                    result = Result.Error(.NetworkRequestFailure)
                }

                completion(result) // ERROR here Closure use of non-escaping parameter 'completion' may allow it to escape
            })
    })
}

但是我进入了 completion(result) 的行和 Closure use of non-escaping parameter 'completion' may allow it to escape

的错误

但是闭包已经在方法 public init(operation: @escaping (Completion) -> Void) 中标记为 @escaping 但可能是因为它是一个将闭包作为参数的闭包并且 returns void 需要另一个注释,所以在 Swift 3 中执行此操作,因为看起来代码曾经在 Swift 2

中工作

[...] but maybe because it's a closure that takes a closure as argument and returns void needs another annotation [...]

你是对的。 Completion 属于 (ResultType) -> Void 类型,因为它是 AsyncOperation 函数类型的参数,这意味着它在默认情况下是非转义的——这意味着您无法捕获 completion转义闭包中的参数(例如传递给 DispatchQueue.main.async)的参数。

因此您需要将 Completion 注释为 @escaping:

public typealias AsyncOperation = (@escaping Completion) -> Void

并且您希望 init(operation:)start(completion:) 函数看起来像这样:

public init(operation: @escaping AsyncOperation) {
    self.operation = operation
}

// the completion: parameter needs to be escaping as it's going to be called after 
// an async operation has completed.
public func start(completion: @escaping Completion) {
    self.operation { result in
        completion(result)
    }
}