文章系列
《RACSignal 》
《RACDisposable》
《RACSubject、RACReplaySubject》
《iOS RAC - 基本用法》
《iOS RAC - 定時(shí)器》
《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 />
結(jié)合一個(gè)案例去來完成這個(gè)功能,完成一個(gè)發(fā)送驗(yàn)證碼的功能。
這里就不討論普通的做法如何去完成這個(gè)事情了,直接上RAC代碼。
功能分析:UI上面會有一個(gè)button
,點(diǎn)擊button
發(fā)送驗(yàn)證碼,并且開始倒計(jì)時(shí),在規(guī)定時(shí)間內(nèi)不允許在此發(fā)送驗(yàn)證碼(也就是不允許點(diǎn)擊button
)
1、搭建UI
2、把button
拖入到ViewControlle
中
3、監(jiān)聽按鈕點(diǎn)擊事件
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
}];
4、在點(diǎn)擊方法中完成如下代碼
@weakify(self)
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self)
x.enabled = false;
self.time = 10;
//這個(gè)就是RAC中的GCD
self.dispoable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
_time --;
NSString * title = _time > 0 ? [NSString stringWithFormat:@"請等待 %d 秒后重試",_time] : @"發(fā)送驗(yàn)證碼";
[self.btn setTitle:title forState:UIControlStateNormal | UIControlStateDisabled];
self.btn.enabled = (_time==0)? YES : NO;
if (_time == 0) {
[self.dispoable dispose];
}
}];
}];
運(yùn)行效果如下:
<br />
<br />
可以看到完美的把功能實(shí)現(xiàn)了,并且代碼都寫在一塊,但是想去看看內(nèi)部是怎么樣處理的嘛?
開始剖析他:
點(diǎn)擊方法進(jìn)入內(nèi)部實(shí)現(xiàn)
+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler {
return [[RACSignal interval:interval onScheduler:scheduler withLeeway:0.0] setNameWithFormat:@"+interval: %f onScheduler: %@", (double)interval, scheduler];
}
點(diǎn)擊進(jìn)來,發(fā)現(xiàn)調(diào)用的是下面的那個(gè)方法
+ (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];
}
在這個(gè)方法里面創(chuàng)建了一個(gè)RACSignal
,當(dāng)外部訂閱的時(shí)候就會調(diào)用scheduler
的after...
方法,在返回的回調(diào)中發(fā)送數(shù)據(jù)。
<br />
到這里為止還是不知道他內(nèi)部的定時(shí)器如何實(shí)現(xiàn)的,所以進(jìn)入after...
方法內(nèi)部查看。
<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);
#}];
}
這里面的紅色部分就是關(guān)鍵代碼啦,原來這個(gè)里面內(nèi)部就是調(diào)用的GCD的定時(shí)器。
- 定時(shí)器的
block
就是外界傳進(jìn)來的block
- 創(chuàng)建一個(gè)
RACDisposable
,調(diào)用disposable
方法等時(shí)候就會進(jìn)入創(chuàng)建對象的block
,把定時(shí)器釋放掉
<br />
最后在文中還使用了兩個(gè)宏
@weakify(self)
@strongify(self)
這兩個(gè)宏就是為了解決循環(huán)引用的,且必須配套使用。
相當(dāng)于這樣子的代碼作用
__weak typeof(self) weakSelf = self;
__strong typeof(weakSelf) strongSelf = weakSelf;