PromisedFuture
PromisedFuture 是对 Future/Promise 的轻量级实现。 PromisedFuture
有助于编写可读性和易于理解的异步代码。
通常在处理异步任务时使用回调机制。它在某些情况下应该能完成任务,但通常我们需要执行多个异步操作,因此我们必须在第一个操作的完成块中嵌套第二个操作。但是,当我们有嵌套的回调时,事情开始变得杂乱,代码在可维护性、可读性和控制方面不友好,从而导致“末日金字塔”、回调地狱和错误处理问题。
PromisedFuture 正在抢救,代码将从这个
APIClient.login(email: "[email protected]", password: "myPassword", completion: { result in
switch result {
case .success(let user):
APIClient.userArticles(userID: user.id, completion: { result in
switch result {
case .success(let articles):
APIClient.getArticle(id: articles.last!.id, completion: { result in
switch result {
case .success(let article):
print(article)
case .failure(let error):
print(error)
}
})
case .failure(let error):
print(error)
}
})
case .failure(let error):
print(error)
}
})
变到这个
APIClient.login(email: "[email protected]", password: "myPassword")
.map({$0.id})
.andThen(APIClient.userArticles)
.map({$0.last!.id})
.andThen(APIClient.getArticle)
.execute(onSuccess: { article in
print(article)
}, onFailure: {error in
print(error)
})
功能
- 可连`)可将异步操作链接起来。
- 轻量级,易于使用(仅 ≈ 40 行代码)。
- 完全测试单元。
- 完整文档。
要求
- iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+
- Xcode 9.0+
- Swift 4.0+
示例
要运行示例项目,请克隆仓库,然后打开工作区 PromisedFuture.xcworkspace
,使用 iOS Example
方案运行。
安装
CocoaPods
CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令安装它:
$ gem install cocoapods
要使用 CocoaPods 将 PromisedFuture 集成到您的 Xcode 项目中,请在您的 Podfile
中指定它:
use_frameworks!
pod 'PromisedFuture'
然后,运行以下命令:
$ pod install
Carthage
Carthage 是一个去中心化的依赖管理器,可构建您的依赖关系并提供二进制框架。
您可以使用以下命令使用 Homebrew 安装 Carthage:
$ brew update
$ brew install carthage
要使用 Carthage 将 PromisedFuture 集成到您的 Xcode 项目中,请在您的 Cartfile
中指定它:
github "aladinway/PromisedFuture"
运行 carthage update
来构建框架。然后在您的应用程序目标的“常规”设置选项卡中的“嵌入的二进制文件”部分,从磁盘上的 Carthage/Build 文件夹拖放构建的 PromisedFuture.framework
。
用法
创建一个 Future
:
要用操作(例如网络调用)创建一个 Future
,我们使用
init(operation: @escaping (_ completion:@escaping Completion) -> Void)
- 参数
operation
:Future 应该执行的操作。这通常是异步操作。completion
:操作的结果块。它有操作的Result
作为参数。
- 示例用法
let future = Future(operation: { completion in
// Your operation here to retrieve the value
Alamofire.request("https://httpbin.org/get")
.responseData { response in
switch response.result {
case .success(let value):
// Then in case of success you call the completion
// with the Result passing the value
completion(.success(data))
case .failure(let error):
// or in case of error call the completion
// with the Result passing the error like :
//completion(.failure(error))
}
}
})
您也可以通过 Result
、Value
或 Error
来创建一个 Future
。
使用提供的 Result
初始化一个新的 Future
init(result: Result<Value>)
-
参数
result
:Future 的结果。它可以是一个包含值的成功Result
或包含Error
的失败。
-
示例用法
let future = Future(result: Result.success(12))
使用提供的值初始化一个新的 Future
init(value: Value)
-
参数
value
:Future 的值。
-
示例用法
let future = Future(value: "Hello")
使用提供的 Error
初始化一个新的 Future
init(value: Value)
-
参数
value
:Future 的值。
-
示例用法
let f: Future<Int>= Future(error: NSError(domain: "E", code: 4, userInfo: nil))
执行一个 Future
:
要执行 Future 的操作,我们可以使用以下这些方法
-
func execute(completion: @escaping Completion)
- 参数
completion
:操作的结果块。它有操作的Result
作为参数。
- 参数
-
示例用法
let future = Future(value: 14) future.execute(completion: { result in switch result { case .success(let value): print(value) // it will print 14 case .failure(let error): print(error) } })
-
func execute(completion: @escaping Completion)
- 参数
onSuccess
:操作的成功能域块。它作为操作的值参数。onFailure
:操作的失败能域块。它作为操作的错误参数。
- 参数
-
示例用法
let future = Future(value: 14) future.execute(onSuccess: { value in print(value) // it will print 14 }, onFailure: { error in print(error) })
链式调用多个 Future
:
Future 的强大之处在于可以链式调用异步操作。我们可以使用 andThen
方法链式调用两个依赖于 futures。
-
func andThen<U>(_ f: @escaping (_ value: Value) -> Future<U>) -> Future<U>
- 参数
f
:一个通过传递此 Future 的值来生成新的Future
的函数。
- 参数
-
示例用法
struct User { id: Int } // Let's assume we need to perform two network operations // The first one to get the user id // And the second one to get the user information // we can use `andThen` to chain them let userIdFuture = Future(value: 14) func userFuture(by userId: Int) -> Future<User> { return Future(value: User(id: userId)) } userIdFuture.andThen(userFuture).execute { user in print(user) }
我们还可以使用
map
函数将Future
的结果进行映射func map<T>(_ f: @escaping (_ value: Value) -> T) -> Future<T>
-
参数
f
:一个通过传递此 Future 的值来生成新的Future
的函数
-
示例用法
let stringFuture = Future(value: "http://www.google.com") let urlFuture = stringFuture.map({URL(string: $0)})
阅读
如果您想了解更多关于 Futures
以及如何在网络层中使用 PromisedFuture 与 Alamofire
一起,强烈推荐阅读我的以下文章:
使用 Alamofire 5 和 Codable 在 Swift 4 中编写网络层第 3 部分:使用 Futures/Promises
作者
Alaeddine Messaoudi [email protected]
许可
PromisedFuture 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。