简体   繁体   中英

Why can't I subscribe completed with the signal from flattenMap

The signal for button

    RACSignal *buttonPressedSignal = [_valicodeGetButton rac_signalForControlEvents:UIControlEventTouchUpInside];

I try to flattenMap the signal with a timer signal I create

[[buttonPressedSignal
  flattenMap:^RACStream *(id value) {
      return [Timer timerSignalWithInterval:1 repeateTime:5];
}]
 subscribeNext:^(id x) {
     @strongify(self)
     [self.valicodeGetButton setTitle:[NSString stringWithFormat:@"%@", x] forState:UIControlStateNormal];
} completed:^{
    self.viewModel.isValicodeGetEnabel = YES;
}];

but I can't get into the completed block.

this is the timer signal:

+ (RACSignal *)timerSignalWithInterval:(NSInteger)interval repeateTime:(NSInteger)repeateTime
{
    __block int count = 0;
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [[[RACSignal interval:interval onScheduler:[RACScheduler mainThreadScheduler]]
          take:repeateTime]
         subscribeNext:^(id x) {
             count++;
             [subscriber sendNext:@(repeateTime - count)];
             if (repeateTime - count == 0) {
                 [subscriber sendCompleted];
             }
         }];
        return [RACDisposable new];
    }];
}

Well, the signal you derive from flattenMap won't complete until each of the returned sub-signals complete and the original signal completes (in this case, buttonPressedSignal ).

So even though each of your inner signals are completing properly, you're not going to see a completion for the outer signal until buttonPressedSignal completes as well, which currently isn't going to happen until _valicodeGetButton is deallocated.

As for fixing it, it depends on what you're trying to accomplish. Do you want to do this completion block after each of the inner signals completes? Are you only trying to run it once?

For tracking the inner values, nested subscriptions instead of flattenMap is one easy way to fix this problem, but it's messy. For a nicer solution, check out materialize instead as an alternative that will let you introspect on the inner signal's completion values from "outside" of the flattenMap .

But that is only a speculative solution. I don't really know the intent here.


Side note: you can simplify timerSignalWithInterval:repeateTime: to the following:

// note the changed types here
+ (RACSignal *)timerSignalWithInterval:(NSTimeInterval)interval count:(NSUInteger)count
{
    __block NSUInteger i = 0;
    return [[[RACSignal interval:interval onScheduler:[RACScheduler mainThreadScheduler]] take:count] map:^(id x) {
        return @(i++);
    }];
}

No need to create an explicit subscription just to change the value that the signal sends. (You can also write that using scanWithStart:reduce: and eschew the __block variable altogether, but it's a bit cumbersome in this case due to the boxing.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM