如何在没有嵌套订阅的情况下订阅命令执行信号的完成?

时间:2014-03-13 00:48:49

标签: objective-c reactive-cocoa frp

我尝试了以下但没有成功。使用-subscribeNext:的等价物按预期工作。

// A
[[_viewModel.loginCommand.executionSignals flatten] subscribeCompleted:^{
    NSLog(@"A");
}];

我唯一的工作实现如下:

// B
[_viewModel.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    [loginSignal subscribeCompleted:^{
        NSLog(@"B");
    }];
}];

为什么没有-flatten在" A"中工作,以及如何重写" B"不使用嵌套订阅?

2 个答案:

答案 0 :(得分:10)

-flatten运算符返回仅在所有内部信号都已完成时才完成的信号,这也需要外部信号完成。 -concat也是如此。因此,一旦您应用任何一个运算符,结果信号就不会表示单个完成,只有最终的汇总完成。

替代嵌套订阅,您可以转换内部信号,以便它们发送表示完成的值。一种方法是使用-materialize

[[[_viewModel.loginCommand.executionSignals
    map:^(RACSignal *loginSignal) {
        // Using -ignoreValues ensures only the completion event is sent.
        return [[loginSignal ignoreValues] materialize];
    }]
    concat]
    subscribeNext:^(RACEvent *event) {
        NSLog(@"Completed: %@", event);
    }];

请注意,我使用了-concat而不是-flatten,因为它与RACCommand的默认串行执行的语义相匹配。在这种情况下,它们最终会做同样的事情,-flatten退化为-concat的行为,因为该命令一次只能执行一个信号。

使用-materialize并不是实现此目的的唯一方法,它恰好发送一个表示完成的值,但这可能是您认为对您的用例有重大意义的任何值。

答案 1 :(得分:0)

我只是认为,从技术上讲,成功完成只是将执行状态更改为NO,在-executionSingals至少发送一次值后,执行状态在上次更改为YES后没有错误。 / p>

基于这样的想法,我做了一个类别:

#import "RACCommand+ARLCompletedSignal.h"

@implementation RACCommand (ARLCompletedSignal)

- (RACSignal *)completed
{
    RACSignal *executing = self.executing;
    RACSignal *signals = self.executionSignals;
    RACSignal *errors = self.errors;

    RACSignal *startingExecution = [RACSignal combineLatest:@[executing, [signals take:1]]
                                                     reduce:^id(NSNumber *executing, id _){ return executing; }];

    return [[startingExecution
       ignore:@NO]
       flattenMap:^RACStream *(id value) {
           RACSignal *comletedOrFailed = [[executing ignore:@YES] subscribeOn:[RACScheduler scheduler]];
           return [[[comletedOrFailed take:1] takeUntil:errors] map:^id(id value) { return nil; }];
       }];
}

@end

标题:

@interface RACCommand (ARLCompletedSignal)

@property (nonatomic, readonly) RACSignal *completed;

@end

当命令成功完成其操作时,-comleted发送nil。 同样在https://gist.github.com/slabko/546de430a16994a5da8e你可以找到版本,如果操作成功完成则发送YES,否则发送NO。

我在一些非常简单的案例中尝试过它并且有效。请告诉我,如果它不适合你的话。

然而,我相信,在大多数情况下,在将原始信号传递给命令之前,订阅原始信号的完成是最好的,“无懈可击”的选项。