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)
}
}
我正在尝试使用 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)
}
}