ReactiveCocoa实现验证码倒计时

有时候需要时间验证码倒计时,以前在没有使用rac的时候我是这么写的:

 __block int timeout = [time intValue];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
    if(timeout<=0){
        dispatch_source_cancel(_timer);
        dispatch_async(dispatch_get_main_queue(), ^{
            // 倒计时完成
            [self.codeButton setTitle:@"获取验证码" forState:UIControlStateNormal];
            self.codeButton.enabled = YES;
        });
    }else{
        int seconds = timeout;
        NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds];
        dispatch_async(dispatch_get_main_queue(), ^{
           // 更新button上的倒计时
             [self.codeButton setTitle:[NSString stringWithFormat:@"%@秒后重新获取",strTime] forState:UIControlStateNormal];
           self.codeButton.enabled = NO;
        });
        timeout--;
    }
});
dispatch_resume(_timer);

用GCD这么写比较蛋疼,更好的办法,肯定有的,但是因为项目的原因没有再研究,直到用到了ReactiveCocoa后,我不由得思考,如何更简单的实现这个功能:

  • 将倒计时本身给抽取出来;
  • 将按钮的enabled给独立出来;

    @weakify(self);
    static NSInteger number = 0;
    RACSignal *timerSignal = [[[RACSignal interval:1.0f onScheduler:[RACScheduler mainThreadScheduler]] map:^id(NSDate *date){
        @strongify(self);
        if (--number <= 0) {
            [self.codeButton setTitle:@"获取验证码" forState:UIControlStateNormal];
            return @YES;
        }else{
            [self.codeButton setTitle:[NSString stringWithFormat:@"%d秒后可重新获取", (int)number] forState:UIControlStateNormal];
            return @NO;
        }
    }] takeUntilBlock:^BOOL(id x){
        return number <= 0;
    }];
    
    // 验证码点击
    self.regView.codeButton.rac_command = [[RACCommand alloc]initWithSignalBlock:^RACSignal *(id input) {
        number = kCountDownSeconds;
        return timerSignal;
    }];
    

好处一目了然。