这是一个对 Promises/A+ 规范 的高层次实现,它大量借鉴了 RXPromise 实现。
Cocoapods 是 iOS 和 OSX 应用程序的出色依赖管理器。如果您不熟悉,请查看 Cocoapods 网站 开始使用。
在 Cocoapods 设置完成后,只需将以下内容添加到您的 Podfile 中
pod 'PromiseZ'
并且当您导入库时
#import <PromiseZ/PZPromise.h>
在其核心,Promise 代表一个未确定的结果。例如,在发起网络请求时,数据不会立即可用,请求可以成功并有一个结果,或者由于某些原因失败。Promises 通过一个对象代表所有这些状态和潜在值。
PZPromise
类遵从 <PZThenable>
协议,并符合 Promises/A+ 规范。可以通过 -init
方法进行初始化。
假设我们有一个异步处理的背景方法
- (PZPromise *)doSomethingAsync
{
// This promise will need to be retained somehow so it can be notified of it's eventual value or failed reason.
PZPromise *promise = [PZPromise new];
...
return promise;
}
在最基本的水平上,我们可以通过添加 on-kept 和 on-broken 块来通知方法完成
PZPromise *promise = [self doSomethingAsync];
[promise thenOnKept:^id(id value) {
// Do something with the result
...
return nil; // The return value doesn't matter in this case
} onBroken:^id(NSError *reason) {
// Do something to handle the failure
...
return nil; // The return value doesn't matter in this case
}];
注意,on-kept 和 on-broken 块实际上返回一个值。这是因为 -thenOnKept:onBroken:
方法实际上返回另一个 <PZThenable>
!这个新的 Promise 将根据您从 on-kept 和 on-broken 块返回的内容而定(resolve),或者在您没有提供块的情况下,根据原始 Promise 的结果而定。所以在我们这个例子中,假设我们想在成功结果上执行其他操作
- (PZPromise *)doSomethingElseAsyncWithResult:(id)result
{
...
}
我们不返回 nil
从我们的 on-kept 块,我们可以返回那个 Promise
PZPromise *promiseA = [self doSomethingAsync];
PZPromise *promiseB = [promise thenOnKept:^id(id value) {
// We return the next promise we want to execute
return [self doSomethingElseAsyncWithResult:value];
} onBroken:^id(NSError *reason) {
// Do something to handle the failure
...
// We can return an already broken promise so promiseB will also be broken.
return [[PZPromise alloc] initWithBrokenReason:reason];
}];
在这种情况下,promiseB
将在由 doSomethingElseAsyncWithResult:
返回的 Promise 解决时解决。
但是,在我们的例子中,我们并不真正需要 promiseA
,所以我们忽略它并开始链式调用
PZPromise *promise = [[self doSomethingAsync] thenOnKept:^id(id value) {
return [self doSomethingElseAsyncWithResult:value];
} onBroken:^id(NSError *reason) {
...
return [[PZPromise alloc] initWithBrokenReason:reason];
}];
返回的 Promise 只有在 -doSomethingAsync
解决其 Promise 并 -doSomethingElseAsyncWithResult:
解决后才会解决。只要我们需要,我们就可以继续链式调用
PZPromise *promise = [[[self doSomethingAsync] thenOnKept:^id(id value) {
return [doSomethingElseAsyncWithResult:value];
} onBroken:nil] thenOnKept:^id(id value) {
return [doAnotherThingWithAnotherResult:value];
} onBroken:nil] thenOnKept:^id(id value) {
return [doFinalThingWithFinalResult:value];
} onBroken:^id(NSError *error) {
// Handle any of the errors that other promises in the chain encountered
...
return [[PZPromise alloc] initWithBrokenReason:reason];
}];
请注意,我们为 on-broken 块传递了 nil
。记住,on-kept 和 on-broken 块都是可选的。如果它们是 nil
,Promise 会简单地将其状态和值传递给返回的 Promise。这样,最后的 on-broken 块实际上会捕获之前任何 Promise 的失败!对于 on-kept 块也是如此。
-thenOnKept:onBroken:
方法返回的 Promise 与通过 -init
或 +new
创建的 Promise 不同,因为它们的解析取决于初始 Promise 或块的返回值。因此,它们被认为是“已绑定”的,并且 已绑定的 Promise 不能手动保留或中断。在绑定的 Promise 上调用 -keepWithValue:
或 -breakWithReason:
将没有作用。
PZPromise
类只表示 Promise 等式的一部分。另一部分是,为了使其有用,您的异步方法必须生成、返回、保留并中断 PZPromise
示例。具体的实现略超出了本说明文件的范畴(尽管您可以查看示例应用程序以获得一些启发),但通常有几个需要考虑的点
PZPromise
实例。-keepWithValue:
,并传入成功的结果。-breakWithReason:
,并传入表示原因的 NSError。实现中的关键点在于具有异步方法的需要保留其 Promise 并用正确的值(成功或失败)解决正确的 Promise。一旦掌握了这个,一切都很顺利!
高层次概述不够吗?本节将深入探讨有关 PZPromise
实现的一些更微妙的问题。
<PZThenable>
协议定义了 -thenOnKept:onBroken:
方法,该方法的违规者必须实现。虽然 PZPromise
符合此协议,但在需要返回自定义对象而不是常规 PZPromise
的情况下,它被保留为独立状态。尽管如此,通常 PZPromise
类应该足够。
PZPromise
应该是线程安全的,可以在任何线程中解决(调用 -keepWithValue:
或 -breakWithReason:
),无论它们的创建位置如何。PZPromise
已经被保留或中断。