Swift 中最简单的 Future 和 Promises 框架。没有魔法,没有样板代码。
本库从 Objective-C 的 JustPromises 实现开始,并保持代码的极简主义,在此基础上增加了以下内容:
您可以在 Wikipedia 上阅读有关 Future 和 Promises 背后的理论,以下是您入门所需了解的主要内容。
Promis 以其以下特性而自豪:
还存在其他开源解决方案,例如:
Promis 从 Just Eat 的 iOS 团队开发的 JustPromises 的 Objective-C 版本中汲取了灵感,该版本非常简洁和极简,而其他库则更加重量级。
以下示例应概述通过链式调用使用 futures 的主要好处。
let request = URLRequest(url: URL(string: "http://example.com")!)
// starts by hitting an API to download data
getData(request: request).thenWithResult { data in
// continue by parsing the retrieved data
parse(data: data)
}.thenWithResult { parsedData in
// continue by mapping the parsed data
map(data: parsedData)
}.onError { error in
// executed only in case an error occurred in the chain
print("error: " + String(describing: error))
}.finally(queue: .main) { future in
// always executed, no matter the state of the previous future or how the chain did perform
switch future.state {
case .result(let value):
print(String(describing: value))
case .error(let err):
print(String(describing: err))
case .cancelled:
print("future is in a cancelled state")
case .unresolved:
print("this really cannot be if any chaining block is executed")
}
}
示例中使用的函数具有以下签名:
func getData(request: URLRequest) -> Future<Data>
func parse(data: Data) -> Future<[Dictionary<String,AnyObject>]>
func map(data: [Dictionary<String,AnyObject>]) -> Future<[FooBar]>
Promises 和 Futures 利用泛型的力量进行参数化,这意味着 Swift 可以推断结果编译类型。这是 Objective-C 世界中的一个相当大的限制,现在由于语言的静态类型特性,我们可以防止在构建时出现大量问题。 future 的状态是一个枚举,定义如下:
enum FutureState<ResultType> {
case unresolved
case result(ResultType)
case error(Error)
case cancelled
}
Promises 的创建和解决方式如下:
let promise = Promise<ResultType>()
promise.setResult(value)
// or
promise.setError(error)
// or
promise.cancel()
用于链式调用的延续方法如下:
func then<NextResultType>(queue: DispatchQueue? = nil, task: @escaping (Future) -> Future<NextResultType>) -> Future<NextResultType>
func thenWithResult<NextResultType>(queue: DispatchQueue? = nil, continuation: @escaping (ResultType) -> Future<NextResultType>) -> Future<NextResultType> {
func onError(queue: DispatchQueue? = nil, continuation: @escaping (Error) -> Void) -> Future {
func finally(queue: DispatchQueue? = nil, block: @escaping (Future<ResultType>) -> Void)
所有函数都可以接受可选的 DispatchQueue
,用于执行延续块。
包装异步任务的函数应遵循以下模式:
func wrappedAsyncTask() -> Future<ResultType> {
let promise = Promise<Data>()
someAsyncOperation() { data, error in
// resolve the promise according to how the async operations did go
switch (data, error) {
case (let data?, _):
promise.setResult(data)
case (nil, let error?):
promise.setError(error)
// etc.
}
}
return promise.future
}
您可以在返回 future 之前链接一个 onError
延续,以允许内联错误处理,我发现这是一个非常方便的模式。
// ...
return promise.future.onError {error in
// handle/log error
}
使用 then
或 thenWithResult
时,应考虑以下事项:
...}.thenWithResult { data -> Future<NextResultType> in
/**
If a block is not trivial, Swift cannot infer the type of the closure and gives the error
'Unable to infer complex closure return type; add explicit type to disambiguate'
so you'll have to add `-> Future<NextResultType> to the block signature
You can make the closure complex just by adding any extra statement (like a print).
All the more reason to structure your code as done in the first given example :)
*/
print("complex closure")
return parse(data: data)
}
请检查 demo app 中的 GettingStarted playground,以查看上述示例的完整实现。
将 Promis
添加到您的 Podfile
use_frameworks!
target 'MyTarget' do
pod 'Promis', '~> x.y.z'
end
$ pod install
github "albertodebortoli/Promis" ~> "x.y.z"
然后在您的应用程序目标的 *Build Phases* 设置选项卡上,添加一个“New Run Script Phase”。 使用以下内容创建一个运行脚本:
/usr/local/bin/carthage copy-frameworks
并在“Input Files”下添加以下路径:
$(SRCROOT)/Carthage/Build/iOS/Promis.framework
Alberto De Bortoli albertodebortoli.website@gmail.com Twitter: @albertodebo GitHub: albertodebortoli 网站: albertodebortoli.com
Promis 在 Apache 2 许可下可用,以尊重 JustPromises,该库从中汲取了灵感。 有关更多信息,请参见 LICENSE 文件。