iOS开发零散知识RAC框架iOS开发笔记

iOS RAC - 定时器

2017-07-22  本文已影响1275人  Codepgq

文章系列
《RACSignal 》
《RACDisposable》
《RACSubject、RACReplaySubject》
《iOS RAC - 基本用法》
《iOS RAC - 定时器》
《iOS RAC - RACMulticastConnection》
《iOS RAC - RACCommand》
《iOS RAC - 核心方法bind》
《iOS RAC - 集合RACTuple、RACSequence》
《iOS RAC - rac_leftSelector》
《iOS RAC - 映射》
《iOS RAC - 过滤》
《iOS RAC - 登录页面,MVVM》

<br />
结合一个案例去来完成这个功能,完成一个发送验证码的功能。
这里就不讨论普通的做法如何去完成这个事情了,直接上RAC代码。

功能分析:UI上面会有一个button,点击button发送验证码,并且开始倒计时,在规定时间内不允许在此发送验证码(也就是不允许点击button

1、搭建UI

UI

2、把button拖入到ViewControlle

引用

3、监听按钮点击事件

    [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
    }];

4、在点击方法中完成如下代码

@weakify(self)
    [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @strongify(self)
        
        x.enabled = false;
        
        self.time = 10;
        
        //这个就是RAC中的GCD
        self.dispoable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
            _time --;
            NSString * title = _time > 0 ? [NSString stringWithFormat:@"请等待 %d 秒后重试",_time] : @"发送验证码";
            [self.btn setTitle:title forState:UIControlStateNormal | UIControlStateDisabled];
            self.btn.enabled = (_time==0)? YES : NO;
            if (_time == 0) {
                [self.dispoable dispose];
            }
        }];
    }];

运行效果如下:

sendverificationcode.gif

<br />
<br />

可以看到完美的把功能实现了,并且代码都写在一块,但是想去看看内部是怎么样处理的嘛?

开始剖析他:
点击方法进入内部实现


+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler {
    return [[RACSignal interval:interval onScheduler:scheduler withLeeway:0.0] setNameWithFormat:@"+interval: %f onScheduler: %@", (double)interval, scheduler];
}

点击进来,发现调用的是下面的那个方法

+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler withLeeway:(NSTimeInterval)leeway {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(scheduler != RACScheduler.immediateScheduler);

    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [scheduler after:[NSDate dateWithTimeIntervalSinceNow:interval] repeatingEvery:interval withLeeway:leeway schedule:^{
            [subscriber sendNext:[NSDate date]];
        }];
    }] setNameWithFormat:@"+interval: %f onScheduler: %@ withLeeway: %f", (double)interval, scheduler, (double)leeway];
}

在这个方法里面创建了一个RACSignal,当外部订阅的时候就会调用schedulerafter...方法,在返回的回调中发送数据。

<br />
到这里为止还是不知道他内部的定时器如何实现的,所以进入after...方法内部查看。

查看内部实现

<br />

- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(interval > 0.0 && interval < INT64_MAX / NSEC_PER_SEC);
    NSCParameterAssert(leeway >= 0.0 && leeway < INT64_MAX / NSEC_PER_SEC);
    NSCParameterAssert(block != NULL);

    uint64_t intervalInNanoSecs = (uint64_t)(interval * NSEC_PER_SEC);
    uint64_t leewayInNanoSecs = (uint64_t)(leeway * NSEC_PER_SEC);

    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    dispatch_source_set_timer(timer, [self.class wallTimeWithDate:date], intervalInNanoSecs, leewayInNanoSecs);
    # dispatch_source_set_event_handler(timer, block);
    dispatch_resume(timer);

    #return [RACDisposable disposableWithBlock:^{
        #dispatch_source_cancel(timer);
    #}];
}

这里面的红色部分就是关键代码啦,原来这个里面内部就是调用的GCD的定时器。

<br />
最后在文中还使用了两个宏
@weakify(self)
@strongify(self)

这两个宏就是为了解决循环引用的,且必须配套使用。

相当于这样子的代码作用

__weak typeof(self) weakSelf = self;
__strong typeof(weakSelf) strongSelf = weakSelf;
上一篇下一篇

猜你喜欢

热点阅读