How can I subscribe to the completion of a command's execution signals without a nested subscription?

后端 未结 2 1059
清酒与你
清酒与你 2020-12-29 17:56

I tried the following without success. The equivalent using -subscribeNext: works as expected.

// A
[[_viewModel.loginCommand.executionSignals f         


        
相关标签:
2条回答
  • 2020-12-29 18:20

    I just thought, technically, successful completion is just a changing of the execution state to NO, after -executionSingals has sent a value at least once and no error after the execution state changed to YES the last time.

    Based on such a thoughts I made a category:

    #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
    

    Header:

    @interface RACCommand (ARLCompletedSignal)
    
    @property (nonatomic, readonly) RACSignal *completed;
    
    @end
    

    Here -comleted sends nil when the command successfully finishes its operation. Also at https://gist.github.com/slabko/546de430a16994a5da8e you can find the version, which sends YES if operation finishes successfully, or NO if not.

    I tried it in some of my pretty simples cases and it worked. Please, let me know, if it doesn't work for yours.

    However, I believe, in most cases, subscribing to the completion of the original signal, before you pass it to the command, is the best, "hackless" option.

    0 讨论(0)
  • 2020-12-29 18:22

    The -flatten operator returns a signal that completes only when all of the inner signals have completed, which requires the outer signal to complete as well. The same is true of -concat. Because of this, once you apply either operator, the resulting signal has no representation of individual completion, only the final aggregate completion.

    Alternative to nested subscriptions, you could transform the inner signals so that they send a value that signifies completion. One way of doing this is with -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);
        }];
    

    Note that I used -concat instead of -flatten, since it matches the semantics of RACCommand's default serial execution. They ultimately do the same in this case, -flatten degenerates to the behavior of -concat because the command only executes signals one at a time.

    Using -materialize isn't the only way to do this, it just happens to send a value that represents completion, but that could be any value that you find appropriately significant for your use case.

    0 讨论(0)
提交回复
热议问题