Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactiveCocoa: disposing of a repeating signal

I'm trying to understand how to dispose of a RACSignal that is scheduled to run on a background thread.

// Start button
@weakify(self);
[[self.startButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) {
    @strongify(self);
    self.startButton.enabled = NO;
    NSDate *startDate = [NSDate date];
    RAC(self, elapsedTime) = [[[[RACSignal interval:0.1f onScheduler:
                                 [RACScheduler schedulerWithPriority:RACSchedulerPriorityDefault]]
                                startWith:[NSDate date]] map:^id(id value) {
        NSTimeInterval timeInterval = [(NSDate *)value timeIntervalSinceDate:startDate];
        return [NSNumber numberWithDouble:timeInterval];
    }] deliverOn:[RACScheduler mainThreadScheduler]];
}];

// Stop button
[[self.stopButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
    self.startButton.enabled = YES;

    // How do I stop the timer here...???

}];

RAC(self.timeLabel, text) = [RACObserve(self, elapsedTime) map:^id(NSNumber *number) {
    NSString *string = [NSString stringWithFormat:@"%.1f sec. elapsed", number.floatValue];
    return string;
}];

The above code does the following:

  • bind a RACCommand to a button that starts a RACSignal
  • the RACSignal is bound to an NSNumber (elapsedTime) that is sent a new value every 0.1 sec.
  • finally I have a timeLabel bound to the number that let's me display on screen a timer updated every 0.1 seconds.

What I would like to do is being able to start and stop the timer when clicking the START and STOP buttons. Problem is I don't understand how to dispose of the signal.

like image 689
Mike Avatar asked Jan 18 '14 14:01

Mike


2 Answers

Usually when you want to stop a signal from continuing to send events, you'll want to use the takeUntil: operator. This is just a crude example, and could probably use a little more finessing, but this should work:

@weakify(self);
[[self.startButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) {
    @strongify(self);
    self.startButton.enabled = NO;
    NSDate *startDate = [NSDate date];
    RAC(self, elapsedTime) = [[[[[RACSignal interval:0.1f onScheduler:
                                 [RACScheduler schedulerWithPriority:RACSchedulerPriorityDefault]]
                                startWith:[NSDate date]] 
                                takeUntil:[self.stopButton rac_signalForControlEvents:UIControlEventTouchUpInside]] map:^id(id value) {
        NSTimeInterval timeInterval = [(NSDate *)value timeIntervalSinceDate:startDate];
        return [NSNumber numberWithDouble:timeInterval];
    }] deliverOn:[RACScheduler mainThreadScheduler]];
}];
like image 114
Ash Furrow Avatar answered Nov 20 '22 10:11

Ash Furrow


Just using takeWhileBlock and setting a flag like shouldReapeatSignalActive

takeWhileBlock:^BOOL(id x) {
        @strongify(self);
        return shouldReapeatSignalActive;
}

when shouldReapeatSignalActive set to NO, all subscribers will all unsubscribe the signal anymore (unless you resubscribe the signal).

like image 24
user3044484 Avatar answered Nov 20 '22 09:11

user3044484