Swift 3中的未来实现

时间:2016-11-21 19:23:27

标签: swift functional-programming closures swift3 future

我正在尝试使用受this talk启发的Swift 3实现一个小型的未来(promises)库,这是我的实践:

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

但是闭包在方法@escaping中已经标记为public init(operation: @escaping (Completion) -> Void),但也许是因为它是一个闭包,它将一个闭包作为参数并返回void需要另一个注释,所以要做到这一点Swift 3因为看起来代码曾经在Swift 2中工作

1 个答案:

答案 0 :(得分:1)

  

[...]但也许是因为它是一个闭包,它将一个闭包作为参数并返回void需要另一个注释[...]

你是对的。 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)
    }
}