【发布时间】:2013-12-20 23:12:46
【问题描述】:
我想合并两个网络信号,但有一些限制。
让我们调用网络信号 A 和 B。A 确实使用 AFNetworking 在缓存中查找资源并立即返回对该请求的任何响应。 B 也考虑缓存,但可以到远程服务器重新验证响应。
好的,那我想做什么:
请求 A:
- 应该尽快发送下一个。
- 如果 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
]];
}
【问题讨论】:
-
RAC 3.0(尚未发布)有一个操作符-takeUntilReplacement:,它的作用与此非常相似。您可能想查看它的实现以获取想法。
-
@Andi 我昨晚深夜发布了一个答案,但我实际上并没有测试我的建议以确保它有效。好奇它是否会起作用,我今天早上对其进行了测试,发现我对 RAC 在错误/完成时终止订阅的行为做出了错误的假设。简而言之,您似乎无法完全使用
-materialize/-dematerialize抑制错误/完成事件。所以我已经删除了答案。 -
@JustinSpahr-Summers:感谢您的提示 - 不确定它如何涵盖规范,但我会看看它。
标签: objective-c reactive-cocoa