2016-07-15 3 views
1

Я хотел бы запустить несколько независимых сетевых запросов параллельно и подписаться на все запросы (мне все равно, если они завершены или ошибка).Reactive Cocoa Legacy - Как обрабатывать несколько независимых сигналов параллельно?

На данный момент я использовал combineLatest. Таким образом, запросы выполняются параллельно (как я хочу), но когда сигнал посылает error, я получил ошибку в подписке.

Я не могу найти оператора, который позволяет запускать несколько независимых запросов параллельно и слушать, когда все будет сделано.

С уважением

РЕДАКТИРОВАТЬ

В других случаях (где необходимо использовать сигналы индивидуально), мне нужно, чтобы подписаться на ошибку. Поэтому мне все еще нужен мой сигнал, чтобы иметь возможность sendError:.

Мой случай использования заключается в следующем:

С одной стороны, у меня есть приложение, которое может сделать полную синхронизацию. Это запустит все независимые запросы. Мне нужно знать, когда все запросы будут выполнены, чтобы отклонить progressHUD. Меня не волнует, сделали ли мои сигналы sendError или sendCompleted.

Но, с другой стороны, у меня есть несколько кнопок, в которых я могу самостоятельно перезапустить каждый запрос, и в этом случае мне нужно сообщить пользователю, был ли сигнал успешным или неудачным.

ответ

1

Я придумал ответ, используя оператор catch: добавить оператор catch RAC ко всему моему сигналу, которые делают новый [RACSignal empty] в случае, если сигнал терпит неудачу:

NSArray* allSignals = @[signal1, signal2, signal3, signal4]; 
NSMutableArray* optionalSignals = [NSMutableArray array]; 
    for (RACSignal* signal in allSignals) { 
     RACSignal* catchableSignal = [signal catch:^RACSignal *(NSError *error) { 
      return [RACSignal empty]; 
     }]; 
     [optionalSignals addObject:catchableSignal]; 
    } 

return [RACSignal combineLatest:optionalSignals]; 

Это не меняет характер моих отдельных сигналов, и я воспользоваться combineLatest возможностями.

EDIT

Если кто-то имеет более элегантный способ RAC, чтобы обработать для ... в цикле, я до сих пор интересно.

0

Вы можете попробовать этот код:

- (void)getAllItemsWithCompletion:(void (^)())completion { 
     NSArray *signals = [self.allItems.rac_sequence map:^id(Item *item) { 
      return [[[self getForItemSignal:item] doCompleted:^{ 
         //done 
        }] doError:^(NSError *error) { 
         //Change the button title to retry 
        }]; 
    }].array; 

    [[RACSignal combineLatest:signals] subscribeCompleted:^{ 
    NSLog(@"All tasks are done"); 
    }]; 
} 

- (RACSignal *)getForItemSignal:(Item *)item { 
return [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id<RACSubscriber> subscriber) { 
     [APIClient getFeeForItemUUID:item.UUID 
         success:^(Fee *fee) { 
          [subscriber sendNext:@(fee)]; 
          [subscriber sendCompleted]; 
         } 
         failure:^(NSError *error) { 
          [subscriber sendError:error]; 
          [subscriber sendCompleted]; 
         }]; 
    }]; 
} 
+0

Спасибо, я попробую это – darksider

+0

я вижу, вы не делаете отправить сообщение об ошибке, поэтому combineLatest идет в завершенном. Это хорошая идея. Но в некоторых случаях я использую сигнал индивидуально, и в этом случае мне нужно знать, была ли ошибка. Вы знаете, можно ли достичь такого же результата без изменения характера моих сигналов, но, играя с операторами RAC? – darksider

+0

@ darksider, как вы, кнопка отображения также вместе с каждым запросом? –

1

Вы можете использовать rac_sequence и map вместо петли. Кроме того, в вашем случае, используя catchTo будет работать точно так же, как catch, делая код более кратким:

NSArray* allSignals = @[signal1, signal2, signal3, signal4]; 
RACSequence *optionalSignals = [[allSignals rac_sequence] map:^id(RACSignal *signal) { 
      return [signal catchTo:[RACSignal empty]]; 
}]; 

return [RACSignal combineLatest:optionalSignals]; 
Смежные вопросы