В блоке dispatch_async, работающем в очереди gcd DISPATCH_QUEUE_PRIORITY_DEFAULT: я создаю два объекта RACSubject, использую слияние RACSignal: и завершаю подписку. Затем, для целей этого теста (и для воспроизведения сценария в моем реальном коде), я отправляю sendComplete на оба из них. Подписка на завершение объединенного сигнала никогда не срабатывает. Я прикрепил к темам две подписки на завершение самостоятельно, они действительно срабатывают. Если я сделаю этот же тест в основном потоке вместо очереди gcd, он будет работать, как и ожидалось.
Есть ли способ заставить это работать, или мне придется провести рефакторинг, чтобы все мои темы попали в основной поток?
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface rac_signal_testTests: SenTestCase
@end
@implementation rac_signal_testTests
- (void)setUp
{
[super setUp];
// Set-up code here.
}
- (void)tearDown
{
// Tear-down code here.
[super tearDown];
}
-(void)test_merged_subjects_will_complete_on_main_thread{
RACSubject *subject1 = [[RACSubject subject] setNameWithFormat:@"subject1"];
RACSubject *subject2 = [[RACSubject subject] setNameWithFormat:@"subject2"];
RACSignal *merged = [RACSignal merge:@[subject1, subject2]];
__block BOOL completed_fired = NO;
[merged subscribeCompleted:^{
completed_fired = YES;
}];
[subject1 sendNext:@"1"];
[subject2 sendNext:@"2"];
[subject1 sendCompleted];
[subject2 sendCompleted];
STAssertTrue(completed_fired, nil);
}
//test proving that throttling isn't breaking the merged signal (initial hypothesis).
-(void)test_merged_subjects_will_complete_if_one_of_them_has_a_throttled_subscriber_on_main_thread{
RACSubject *subject1 = [[RACSubject subject] setNameWithFormat:@"subject1"];
RACSubject *subject2 = [[RACSubject subject] setNameWithFormat:@"subject2"];
__block NSString * hit_subject2_next = nil;
[[subject2 throttle:.5] subscribeNext:^(NSString *value){
hit_subject2_next = value;
}];
RACSignal *merged = [RACSignal merge:@[subject1, subject2]];
__block BOOL completed_fired = NO;
[merged subscribeCompleted:^{
completed_fired = YES;
}];
[subject2 sendNext:@"2"];
[subject2 sendCompleted];
[subject1 sendCompleted];
STAssertEqualObjects(@"2", hit_subject2_next, nil);
STAssertTrue(completed_fired, nil);
}
-(void)test_merged_subjects_will_complete_if_on_gcd_queue{
__block BOOL complete = NO;
dispatch_queue_t global_default_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(global_default_queue, ^{
RACSubject *subject1 = [[RACSubject subject] setNameWithFormat:@"subject1"];
RACSubject *subject2 = [[RACSubject subject] setNameWithFormat:@"subject2"];
__block NSString * hit_subject2_next = nil;
RACScheduler *global_default_scheduler = [RACScheduler schedulerWithQueue:global_default_queue name:@"com.test.global_default"];
RACSignal *sig1 = [subject1 deliverOn:RACScheduler.mainThreadScheduler];
RACSignal *sig2 = [subject2 deliverOn:RACScheduler.mainThreadScheduler];
[sig2 subscribeNext:^(NSString *value){
hit_subject2_next = value;
}];
[sig2 subscribeCompleted:^{
NSLog(@"hit sig2 complete");
}];
[sig1 subscribeCompleted:^{
NSLog(@"hit sig1 complete");
}];
RACSignal *merged = [[RACSignal merge:@[sig1, sig2]] deliverOn:RACScheduler.mainThreadScheduler];
[merged subscribeCompleted:^{
complete = YES;
}];
[subject2 sendNext:@"2"];
// if we dispatch the send complete calls to the main queue then this code works but that seems like it shoul be unnecessary.
// dispatch_async(dispatch_get_main_queue(), ^{
[subject1 sendCompleted];
[subject2 sendCompleted];
// });
});
NSDate *startTime = NSDate.date;
do{
[NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:.5]];
}while(!complete && [NSDate.date timeIntervalSinceDate:startTime] <= 10.0);
STAssertTrue(complete, nil);
}
@end