最近一段時(shí)間開始研究RAC荔泳,它集響應(yīng)式編程,函數(shù)式編程和鏈?zhǔn)骄幊逃谝簧砼氨俜降恼f(shuō)玛歌,ReactiveCocoa(其簡(jiǎn)稱為RAC)是由GitHub開源的一個(gè)應(yīng)用于iOS和OS X開發(fā)的新框架,大大簡(jiǎn)化了我們的代碼擎椰,提高了代碼的安全性支子,很多處理已經(jīng)幫我們做好了,比如block里面循環(huán)引用的問(wèn)題达舒,最終在我們?nèi)∠嗛喌哪且粍x那值朋,幫我們打斷了循環(huán)引用。
首先巩搏,如何安裝RAC昨登,直接通過(guò)pods進(jìn)行安裝即可,現(xiàn)在RAC已經(jīng)支持swift贯底,這里我們就直接基于OC的講解吧丰辣。
推薦RAC的版本3.0.0,通過(guò)pod安裝好后禽捆,build一下看看有沒有問(wèn)題糯俗,一般情況式?jīng)]啥問(wèn)題的。
現(xiàn)在一起開啟RAC的愉快之旅吧睦擂。
由于RAC的功能實(shí)在是太強(qiáng)大了得湘,涉及到一整套的編程邏輯,比如數(shù)據(jù)結(jié)構(gòu)方面顿仇,增加了元祖類型RACTuple淘正,RACSequence;數(shù)據(jù)處理方面,快速遍歷數(shù)組臼闻,字典(非常好的字典轉(zhuǎn)模型設(shè)計(jì))鸿吆,監(jiān)聽各種事件,文本框輸入述呐,代替通知惩淳,代理,KVO等等,網(wǎng)絡(luò)事件的處理,比如一個(gè)頁(yè)面多個(gè)請(qǐng)求完成后刷新頁(yè)面等等思犁,還有非常牛逼的宏(當(dāng)然我沒看懂代虾,不建議大家去看,會(huì)用就好了激蹲,看了會(huì)瘋掉的)棉磨,列舉了這么多,其實(shí)最根本的就是信號(hào)的處理学辱,所有的事件都是先轉(zhuǎn)化成一個(gè)信號(hào)RACSignal乘瓤,再訂閱信號(hào)來(lái)完成的。
知識(shí)點(diǎn)一:
數(shù)據(jù)結(jié)構(gòu)策泣,元祖類衙傀,RACTuple,比較類似于OC中的數(shù)組萨咕,用法上也大同小異统抬,可以存放任何類型的對(duì)象。
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"aaa",@"bbb",@(123)]];
知識(shí)點(diǎn)二:快速遍歷數(shù)組
數(shù)據(jù)結(jié)構(gòu)任洞,RACSequence蓄喇,用于代理NSArray,NSDictionary交掏,主要用途是進(jìn)行快速遍歷累驮,最常用的場(chǎng)景就是字典轉(zhuǎn)模型让虐。
NSArray *arr = @[@"abc",@"bbb",@123];
RACSequence *requence = arr.rac_sequence; // ?字典或數(shù)組都可以直接轉(zhuǎn)化成RACSequence類型的對(duì)象
// 遍歷
RACSignal *signal = requence.signal; // 再拿到這個(gè)對(duì)象的信號(hào)屬性進(jìn)行遍歷
[signal subscribeNext:^(id? _Nullable x) {NSLog(@"%@",x);}];
// 快速寫法:
[arr.rac_sequence.signal subscribeNext:^(id? _Nullable x) {}];
知識(shí)點(diǎn)三:快速遍歷字典
// 字典
NSDictionary *dict = @{@"name":@"Hank",@"age":@18};
// 字典轉(zhuǎn)集合,遍歷厌衔,其中的x其實(shí)就是元祖類型真友,拿到元祖RACTuple即可進(jìn)行拆包處理
[dict.rac_sequence.signal subscribeNext:^(id? _Nullable x) {
//? ? ? ? NSLog(@"%@",x);
// 發(fā)送了元祖類型 RACTwoTuple
//? ? ? ? RACTwoTuple *tuple = (RACTwoTuple *)x;
//? ? ? ? NSString *key = tuple[0];
//? ? ? ? NSString *value = tuple[1];
// 宏挪鹏,用于解析元祖,參數(shù):需要解析的元祖见秽,拆包去處鍵值數(shù)據(jù)
RACTupleUnpack(NSString *key,NSString *value) = x;
NSLog(@"%@%@",key,value);
}];
知識(shí)點(diǎn)四:舉例應(yīng)用場(chǎng)景:快速遍歷,數(shù)據(jù)轉(zhuǎn)模型并封裝成數(shù)組
// 解析plist文件
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"KFC.plist" ofType:nil];
NSArray *dictArray = [[NSArray alloc]initWithContentsOfFile:filePath];
// 字典轉(zhuǎn)模型讨盒,解決方案一
//? ? NSMutableArray *array = [[NSMutableArray alloc]init];
//? ? [dictArray.rac_sequence.signal subscribeNext:^(NSDictionary *? _Nullable x) {
//? ? ? ? KFC *kfc = [KFC KFCWithDict:x];
//? ? ? ? [array addObject:kfc];
//? ? }];
// 解決方案二:通過(guò)映射解取,可以知道里面是字典,所以寫字典
// 會(huì)將集合中的所有元素value映射成新的對(duì)象[KFC KFCWithDict:value]返顺,然后包裝在一個(gè)數(shù)組里面
NSArray *arr = [[dictArray.rac_sequence map:^id _Nullable(NSDictionary * value) {
// 返回一個(gè)模型
return [KFC KFCWithDict:value];
// 轉(zhuǎn)成數(shù)組禀苦,拿到數(shù)據(jù)直接用是不是很方便啊K烊怠U穹Α!
}]array];
NSLog(@"%@",arr);
知識(shí)點(diǎn)五: 取代代理秉扑,監(jiān)聽某個(gè)類的事件
一般我們?cè)跈?quán)衡數(shù)據(jù)回調(diào)時(shí)慧邮,會(huì)傾向于使用block進(jìn)行回調(diào),但是對(duì)于一些事件的處理,比如點(diǎn)擊事件误澳,去重寫block或者代理耻矮,顯得十分麻煩,這里推薦使用RAC來(lái)解決脓匿。
比如淘钟,監(jiān)聽一個(gè)類的點(diǎn)擊事件或者某個(gè)事件的執(zhí)行宦赠,
// 1.代替代理:RACSubject
// 監(jiān)聽blueView里面的哪個(gè)方法的調(diào)用
[[self.blueView rac_signalForSelector:@selector(laile:)]subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"dianjile:%@",x);
}];
[[self.blueView rac_signalForSelector:@selector(btnClick:)]subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"dianjile:%@",x);
}];
}
知識(shí)點(diǎn)六:取代KVO
原生的KVO是將監(jiān)聽和監(jiān)聽后的處理分開陪毡,并且還要在一個(gè)類的dealloc方法里面進(jìn)行注銷觀察者,顯得非常麻煩勾扭,而RAC很好的幫我們處理好了一切毡琉,見下面:
// 監(jiān)聽方案一:
[_blueView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
// 監(jiān)聽的回調(diào)
// 好處:將多個(gè)監(jiān)聽分開,也不需要擔(dān)心觀察者的移除
NSLog(@"value:%@---change:%@",value,change);
}];
// 監(jiān)聽方案2:
// 創(chuàng)建一個(gè)監(jiān)聽的信號(hào)
//? ? [[_blueView rac_valuesForKeyPath:@"frame" observer:nil
//? ? ? ] subscribeNext:^(id? _Nullable x) {
//? ? ? ? NSLog(@"%@",x);
//? ? }];
知識(shí)點(diǎn)七:監(jiān)聽當(dāng)前控制器的某個(gè)事件:
// 代替Controller的監(jiān)聽事件
[[_btn rac_signalForControlEvents:(UIControlEventTouchUpInside)]subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@",x);
}];
知識(shí)點(diǎn)八:取代通知中心
// 代理通知
[[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardWillShowNotification object:nil]subscribeNext:^(NSNotification * _Nullable x) {
// 全部轉(zhuǎn)化成了信號(hào)
NSLog(@"%@",x);
}];
知識(shí)點(diǎn)九:監(jiān)聽文本框的輸入
// 監(jiān)聽文本框:拿到文本框輸入的每次的值
[_textView.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
知識(shí)點(diǎn)十:RAC的timer計(jì)時(shí)器
原生的NSTimer用起來(lái)比較麻煩, 創(chuàng)建后需要手動(dòng)的停止妙色,釋放桅滋,而RAC也很好的幫我們處理好了一切:
// RAC的timer
[[RACSignal interval:1.0 onScheduler:[RACScheduler scheduler]]subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",[NSThread currentThread]);
}];
知識(shí)點(diǎn)十一:RAC處理網(wǎng)絡(luò)請(qǐng)求事件,比如一個(gè)頁(yè)面有多個(gè)接口身辨,需要一起刷新UI時(shí)丐谋。
/ 請(qǐng)求數(shù)據(jù)? ? RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id_Nonnull subscriber) {? ??
? ? // 請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)? ? ? ? NSLog(@"請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù) 1");? ? ?
?? // 發(fā)送數(shù)據(jù)? ? ? ? [subscriber sendNext:@"發(fā)送數(shù)據(jù) 1"];? ? ??
? return nil;??
? }];? ? ??
? RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id_Nonnull subscriber) {
// 請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)
NSLog(@"請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù) 2");
// 發(fā)送數(shù)據(jù)
[subscriber sendNext:@"發(fā)送數(shù)據(jù) 2"];
return nil;
}];
// 訂閱信號(hào)后就會(huì)收到信號(hào)發(fā)出的內(nèi)容
//? ? [signal1 subscribeNext:^(id? _Nullable x) {
//? ? ? ? NSLog(@"處理數(shù)據(jù) 1");
//? ? }];
// 數(shù)組:存放信號(hào)
// 當(dāng)數(shù)組中所有信號(hào)都發(fā)送了數(shù)據(jù),才會(huì)執(zhí)行selector煌珊,必須帶參,參數(shù)是sendNext發(fā)送過(guò)來(lái)的号俐,必須和信號(hào)一一對(duì)應(yīng)
// 參數(shù):每個(gè)信號(hào)發(fā)送的數(shù)據(jù),這里必須要帶參數(shù)定庵,不然會(huì)崩潰
[self rac_liftSelector:@selector(updateUIWithOneData:twoData:) withSignalsFromArray:@[signal1,signal2]];
知識(shí)點(diǎn)十二:RAC里面的宏
RAC里面的宏可以分為以下幾類:
/**
* RAC,給某個(gè)對(duì)象綁定一個(gè)屬性
* RACObserver吏饿,監(jiān)聽某個(gè)對(duì)象的屬性
* RACTuplePack:將數(shù)據(jù)打包成RACTuple
* RACTupleUnpack: 將RAC元祖解包成數(shù)據(jù)
*/
比如RAC宏用法:
// 監(jiān)聽文本框內(nèi)容
//? ? [self.textfield.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
//? ? ? ? _label.text = x;
//? ? }];
// 宏RAC,給某個(gè)對(duì)象的某個(gè)屬性綁定信號(hào),一旦信號(hào)產(chǎn)生數(shù)據(jù)蔬浙,就會(huì)將內(nèi)容賦值給屬性
RAC(_label,text) = self.textfield.rac_textSignal;
// 監(jiān)聽某個(gè)對(duì)象的某個(gè)屬性猪落,返回信號(hào)
// 只要這個(gè)對(duì)象的屬性發(fā)生變化,信號(hào)就發(fā)送數(shù)據(jù)
[RACObserve(self.label, text)subscribeNext:^(id? _Nullable x) {
NSLog(@"%@",x);
}];