I have two network signals that I want to merge, but with some restrictions.
Let us call the network signals A and B. A does use AFNetworking to look up a resource in the cache and return any response for that request immediately. B also considers the cache, but can go to the remote server for revalidation of the response.
Ok, so what I want to do:
Request A:
- should do sendNext as soon as possible.
- if B already has done a sendNext, we will just ignore A.
- if something goes wrong, and A creates an error, we should just ignore it.
Request B:
- should do sendNext as soon as possible, even if A already has done a sendNext.
- if something goes wrong, I am interessed in the error from B, but it should not stop A.
My current solution is this:
- (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;
}
I know that this solution does not fulfill my requirements, so I wonder if anyone could help me with a better solution.
My solution (derived from @JustinSpahr-Summers answer):
- (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
]];
}