2013-04-03 5 views
3

Рассмотрим следующий фрагмент кода:ReactiveCocoa takeUntil и TakeWhile не посылает последний «следующий»

- (RACSignal *)startRouting { 
... 
} 

- (RACSignal *)updateRoutingWithSession:(NSString *)session { 
... 
} 

- (RACSignal *)fetchFlights { 
    return [[self startRouting] flattenMap:^RACStream *(NSString *session) { 
     return [[[[self updateRoutingWithSession:session] 
         delay:2.0f] 
         repeat] 
         takeUntilBlock:^BOOL(RACTuple *operationAndResponse) { 
          AFHTTPRequestOperation *operation = [operationAndResponse first]; 
          NSDictionary *response = [operationAndResponse second]; 
          return [operation isCancelled] || 100 == [response[kPercentComplete] intValue]; 
         }]; 
    }]; 
} 

То, что здесь происходит, что startRouting возвращает RACSignal, который отправляет идентификатор сеанса. updateRoutingWithSession: возвращает RACSignal, который отправляет NSDictionary, включая атрибут PercentComplete. Между опросами есть две секунды.

fetchFlights будет работать до updateRoutingWithSession: имеет PercentComplete из 100.

Мой вопрос в том, что самый последний sendNext:, где takeUntilBlock возвращается true, не достигает RACSubscriber.

Что мне не хватает?

ответ

2

Я нашел это в мире RX. Это обычно решается путем слияния двух сигналов. Тот, который берет повторяющийся источник, пока предикат не будет истинным. А другой, который пропускает, когда предикат является истинным.

Это выглядит как этот

BOOL (^finished)(id _) = ^BOOL(id _) { 
    return predicate; // BOOLean here 
} 

// You want a multicast signal, because multiple signals will subscribe to the source. 
// Multicasting it means that you won't get repeated api-requests, in this case. 
RACMulticastConnection *source = [[theSignal repeat] publish]; 

RACSignal *whileNotDone = [source.signal takeUntilBlock:finished]; 
RACSignal *whenDone = [[source.signal skipUntilBlock:finished] take:1]; 
RACSignal *merged = [RACSignal merge:@[whileNotDone, whenDone]]; 

[source connect]; // Needed for a multicast signal to initiate. 

The merged сигнал будет sendNext каждый next в source, включая самого последнего. Затем sendCompleted.

Некоторые ссылки из мира RX:

1

Чтобы уточнить: ваша проблема в том, что next, который запускает завершение, не отправляется? takeUntilBlock будет распространять следующие сообщения до тех пор, пока предикат не станет НЕТ. (documentation) Поэтому последние next не будут отправлены. Но вы можете подписаться на completion, который должен произойти в этом случае.

+0

Совершенно верно. То, что я могу сделать, это не использовать takeUntilBlock и вместо этого переместить предикат в updateRoutingWithSession: и только sendComplete: однажды PercentComplete равен 100. Но это нарушит логический поток updateRoutingWithSession: который не обращает внимания на то, как его используют функции более высокого порядка, т.е. не осознавая, что идея состоит в том, чтобы опросить службу до завершения. –

+0

@HansSjunnesson Я думаю, @allprog пытается указать, что вы можете использовать событие 'completed' здесь, чтобы узнать, когда' takeUntilBlock: 'возвращает' NO'. Вы можете сделать это через '-subscribeCompleted:' или оператор, такой как [-sequenceNext:] (https://github.com/ReactiveCocoa/ReactiveCocoa/blob/2b98e161af39dd11f1a00ca35fae1607dbb6b0ee/ReactiveCocoaFramework/ReactiveCocoa/RACSignal%2BOperations.h#L163-L164) , –

+0

@ JustinSpahr-Summers True, но завершенный не отправляет никаких данных. Меня интересует содержимое последнего, заполняя значение, которое посылает сигнал. TakeWhile подавляет распространение этого последнего 'next'. –