文章系列
《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
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];
}
}];
}];
运行效果如下:
<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
,当外部订阅的时候就会调用scheduler
的after...
方法,在返回的回调中发送数据。
<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的定时器。
- 定时器的
block
就是外界传进来的block
- 创建一个
RACDisposable
,调用disposable
方法等时候就会进入创建对象的block
,把定时器释放掉
<br />
最后在文中还使用了两个宏
@weakify(self)
@strongify(self)
这两个宏就是为了解决循环引用的,且必须配套使用。
相当于这样子的代码作用
__weak typeof(self) weakSelf = self;
__strong typeof(weakSelf) strongSelf = weakSelf;