归根结底,使用“完成处理程序”的传统方法的代码的简化版本可能如下所示:
fetchOAuthToken() { (token, error) in
if let token = token {
fetchPrivileges(token: token) { (privileges, error) in
if let privileges = privileges {
fetchData(token: token, privileges: privileges) { (data, error) in
if let data = data {
// ...
}
}
}
}
}
}
请注意,仅为简洁起见,代码不包含错误处理,也没有取消方法。
依赖关系是通过延续建立的——即完成处理程序。
另一种使用“类 Scala”期货的方法如下所示(使用Promises是非常相似的方法):
fetchOAuthToken().flatMap { token in
fetchPrivileges(token: token).flatMap { privileges in
fetchData(token: token, privileges).map { data in
// ...
}
}
}.onFailure { error in
print("Error: \(error)")
}
上面的语句创建了一个由三个组成的任务。
这种方法包含完整的错误处理,即使它可能并不明显。生产版本与上面的这段代码没有太大区别——它可能只是增加了一种取消的方法。
有一些第三方库实现了类似 Scala 的期货或承诺。
添加取消的一种方法可能如下所示:
let cr = CancellationRequest()
fetchOAuthToken(ct: cr.token).flatMap { token in
fetchPrivileges(token: token, ct: cr.token).flatMap { privileges in
fetchData(token: token, privileges, ct: cr.token).map { data in
// ...
}
}
}.onFailure { error in
print("Error: \(error)")
}
稍后,您可以取消组合任务(当前正在执行的任务):
cr.cancel()
笔记:
这个问题也可以用 解决NSOperations
。但是,它需要 的三个子类NSOperation
,以及一个或两个线程安全的帮助类,它们将用于将 Op1 的结果“传输”到 Op2 的输入,并将 Op2 的结果“传输”到 Op3 的输入。我估计这将需要大约 500 行代码——对于 SO 的答案来说太多了;)
“类似 Scala”的期货方法需要第三方库。取消需要另一个 - 或您自己的实现(这并不难),或者一个提供所有功能的库。