gpt4 book ai didi

objective-c - 如何使用 ReactiveCocoa 组合两个异步网络调用

转载 作者:太空狗 更新时间:2023-10-30 03:31:51 25 4
gpt4 key购买 nike

我有两个网络信号要合并,但有一些限制。

让我们将网络信号称为 A 和 B。A 确实使用 AFNetworking 在缓存中查找资源并立即返回对该请求的任何响应。 B 也考虑了缓存,但可以去远程服务器重新验证响应。

好的,所以我想做的是:

请求 A:

  • 应该尽快执行 sendNext。
  • 如果 B 已经完成了 sendNext,我们将忽略 A。
  • 如果出现问题,并且 A 造成了错误,我们应该忽略它。

请求 B:

  • 应该尽快执行 sendNext,即使 A 已经执行了 sendNext。
  • 如果出现问题,我对 B 的错误很感兴趣,但它不应该阻止 A。

我目前的解决方案是这样的:

- (RACSignal *)issueById:(NSString *)issueId {

RACSignal *filterSignal = [RACSignal createSignal:^RACDisposable *(id <RACSubscriber> subscriber) {
RACSignal *cacheSignal = [[IssueWSRequest instance] issueWithId:issueId cachePolicy:NSURLRequestReturnCacheDataDontLoad];

return [cacheSignal subscribeNext:^(id x) {
[subscriber sendNext:x];
} error:^(NSError *error) {
NSLog(@"Ignore error");
[subscriber sendCompleted];
} completed:^{
[subscriber sendCompleted];
}];
}];

RACSignal *remoteSignal = [[IssueWSRequest instance] issueWithId:issueId cachePolicy:NSURLRequestUseProtocolCachePolicy];

RACSignal *combined = [RACSignal merge:@[newSign, remoteSignal]];
return combined;
}

我知道这个解决方案不能满足我的要求,所以我想知道是否有人可以帮助我提供更好的解决方案。

我的解决方案(源自@JustinSpahr-Summers 的回答):

- (RACSignal *)issueById:(NSString *)issueId {

RACSubject *localErrors = [RACSubject subject];

RACSignal *remoteSignal = [[IssueWSRequest instance] issueWithId:issueId cachePolicy:NSURLRequestUseProtocolCachePolicy];

RACSignal *cacheSignal = [[[[[[IssueWSRequest instance] issueWithId:issueId cachePolicy:NSURLRequestReturnCacheDataDontLoad]
takeUntil:remoteSignal] doError:^(NSError *error) {
[localErrors sendNext:error];
}] finally:^{
// Make sure to complete the subject, since infinite signals are
// difficult to use.
[localErrors sendCompleted];
}]
replayLazily];

return [RACSignal merge:@[
[cacheSignal catchTo:[RACSignal empty]],
remoteSignal
]];
}

最佳答案

这是一个很难回答的问题,因为您想要的错误处理从根本上与 RACSignal API 契约不兼容,后者声明 errors have exception semantics .

忽略但仍然关心错误的唯一方法是将它们重定向到别处。在这个例子中,我将使用一个主题:

RACSubject *remoteErrors = [RACSubject subject];

……但您也可以使用属性或其他一些通知机制。

我将继续使用您在上面提供的 remoteSignalcacheSignal,并进行一些修改。这是我们希望他们的行为:

  1. remoteSignal 应该将它的错误发送到 remoteErrors
  2. cacheSignal 应在 remoteSignal 发送值后立即取消
  3. 任一信号的错误不应终止另一个信号
  4. 我们想合并来自cacheSignalremoteSignal的值,这样在读取缓存后我们仍然得到远程值

考虑到这一点,让我们看一下remoteSignal:

RACSignal *remoteSignal = [[[[[IssueWSRequest
instance]
issueWithId:issueId cachePolicy:NSURLRequestUseProtocolCachePolicy]
doError:^(NSError *error) {
[remoteErrors sendNext:error];
}]
finally:^{
// Make sure to complete the subject, since infinite signals are
// difficult to use.
[remoteErrors sendCompleted];
}]
replayLazily];

-doError:-finally: 控制remoteErrors 主题,满足我们上面的第一个要求。因为我们需要在不止一个地方使用 remoteSignal(正如您在上面的列表中看到的那样),我们使用 -replayLazily 来确保它的副作用只发生一次.

cacheSignal 几乎没有变化。我们只需要使用 -takeUntil: 来确保它在 remoteSignal 发送一个值时终止(但如果它发送错误则不会):

RACSignal *cacheSignal = [[[IssueWSRequest
instance]
issueWithId:issueId cachePolicy:NSURLRequestReturnCacheDataDontLoad]
takeUntil:remoteSignal];

最后,我们要合并它们的值,这样两个信号同时启动并且它们的值可以按任意顺序到达:

return [RACSignal merge:@[
[cacheSignal catchTo:[RACSignal empty]],
[remoteSignal catchTo:[RACSignal empty]]
];

我们在这里忽略错误,因为任何一个错误都会终止两者(因为它们现在已经合并)。我们的错误处理行为已在上面得到处理。

而且,尽管进行了合并,但在 cacheSignal 上使用 -takeUntil: 可确保它不可能在 remoteSignal 执行后发送值.

再看一下需求列表,您可以看到用于满足每个需求的运算符:

  1. [-doError:] remoteSignal 应将其错误发送至 remoteErrors
  2. [-takeUntil:] cacheSignal 应在 remoteSignal 发送值后立即取消
  3. [-catchTo:] 来自任一信号的错误不应终止另一个信号
  4. [+merge:] 我们想合并来自 cacheSignalremoteSignal 的值,这样我们读取缓存后仍然获取远程值

关于objective-c - 如何使用 ReactiveCocoa 组合两个异步网络调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20375835/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com