I have success notification and a failure notification that come through NSNotificationCenter. I wrote some tests to figure out how to combine the signals from those two notifications into one signal that provides an error when the failure notification hits and a next followed by a complete when the success notification hits.
Currently the complete blocks won't get hit, next and error get hit.
Also, secondary bonus question: why doesn't @[errorNotification, completeNotification].rac_sequence.signal do the same thing as the signal of signal creation below?
Code:
-(void)test_flatten_signal_of_signals_and_convert_notification_to_error{
RACSignal *errorNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"TEST_FAILURE" object:nil] take:1];
errorNotification = [errorNotification flattenMap:^(NSNotification *notification){
return [RACSignal error:[NSError errorWithDomain:@"RAC_TEST" code:1 userInfo:nil]];
}];
RACSubject *completeNotification = [RACSubject subject];
RACSignal *signalOfSignals = [[RACSignal
createSignal:^RACDisposable *(id<RACSubscriber> subscriber){
[subscriber sendNext:errorNotification];
[subscriber sendNext:completeNotification];
[subscriber sendCompleted];
return nil;
}]
flatten];
__block BOOL hitCompleted = NO;
[signalOfSignals
subscribeNext:^(id val){
STFail(nil);
}
error:^(NSError *err){
hitCompleted = YES;
}
completed:^{
STFail(nil);
}];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TEST" object:self];
STAssertTrue(hitCompleted, nil);
}
-(void)test_flatten_signal_of_signals_and_hits_next_complete_on_notification{
RACSubject *errorNotification = [RACSubject subject];
RACSignal *completeNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"TEST_SUCESS" object:nil] take:1];
RACSignal *signalOfSignals = [[RACSignal
createSignal:^RACDisposable *(id<RACSubscriber> subscriber){
[subscriber sendNext:errorNotification];
[subscriber sendNext:completeNotification];
[subscriber sendCompleted];
return nil;
}]
flatten];
__block BOOL hitCompleted = NO;
__block BOOL hitNext = NO;
[signalOfSignals
subscribeNext:^(id val){
hitNext = YES;
}
error:^(NSError *err){
STFail(nil);
}
completed:^{
hitCompleted = YES;
}];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TEST_SUCCESS" object:self];
STAssertTrue(hitCompleted, nil);
STAssertTrue(hitNext, nil);
}
You can do this with built-in operators:
RACSignal *successNotification = [[NSNotificationCenter.defaultCenter
rac_addObserverForName:SuccessNotification object:nil]
take:1];
RACSignal *errorNotification = [[NSNotificationCenter.defaultCenter
rac_addObserverForName:FailureNotification object:nil]
flattenMap:^(NSNotification *notification) {
// Convert to a meaningful error somehow.
NSError *error = …;
return [RACSignal error:error];
}];
RACSignal *signal = [RACSignal merge:@[ successNotification, errorNotification ]];
This takes care of disposal for you, and more obviously indicates how each of the notifications are mapped to a value or an error.
why doesn't @[errorNotification, completeNotification].rac_sequence.signal do the same thing as the signal of signal creation below?
The signal created will send its values asynchronously, unlike the signal you created in your example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With