初級篇簡單的介紹了RAC泽腮。本文將介紹RAC在項目中常見的類和最常用的一些操作方法!!!
一瞒爬、常見類
1牛柒、RACSiganl :信號類务豺。
- RACEmptySignal :空信號蹦狂,用來實現(xiàn) RACSignal 的 +empty 方法誓篱;
- RACReturnSignal :一元信號,用來實現(xiàn) RACSignal 的 +return: 方法鸥咖;
- RACDynamicSignal :動態(tài)信號燕鸽,使用一個 block - 來實現(xiàn)訂閱行為,我們在使用 RACSignal 的 +createSignal: 方法時創(chuàng)建的就是該類的實例啊研;
- RACErrorSignal :錯誤信號,用來實現(xiàn) RACSignal 的 +error: 方法鸥拧;
- RACChannelTerminal :通道終端党远,代表 RACChannel 的一個終端,用來實現(xiàn)雙向綁定富弦。
2沟娱、RACSubscriber :訂閱者
3、RACDisposable :用于取消訂閱或者清理資源腕柜,當(dāng)信號發(fā)送完成或者發(fā)送錯誤的時候济似,就會自動觸發(fā)它。
- RACSerialDisposable :作為 disposable 的容器使用盏缤,可以包含一個 disposable 對象砰蠢,并且允許將這個 disposable 對象通過原子操作交換出來;
- RACKVOTrampoline :代表一次 KVO 觀察唉铜,并且可以用來停止觀察台舱;
- RACCompoundDisposable :它可以包含多個 disposable 對象,并且支持手動添加和移除 disposable 對象
- RACScopedDisposable :當(dāng)它被 dealloc 的時候調(diào)用本身的 -dispose 方法潭流。
4竞惋、RACSubject :信號提供者,自己可以充當(dāng)信號灰嫉,又能發(fā)送信號拆宛。
- RACGroupedSignal :分組信號,用來實現(xiàn) RACSignal 的分組功能熬甫;
- RACBehaviorSubject :重演最后值的信號胰挑,當(dāng)被訂閱時蔓罚,會向訂閱者發(fā)送它最后接收到的值;
- RACReplaySubject :重演信號瞻颂,保存發(fā)送過的值豺谈,當(dāng)被訂閱時,會向訂閱者重新發(fā)送這些值贡这。
5茬末、RACTuple :元組類,類似NSArray,用來包裝值.
6、RACSequence: RAC中的集合類
7盖矫、RACCommand: RAC中用于處理事件的類丽惭,可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞,包裝到這個類中辈双,他可以很方便的監(jiān)控事件的執(zhí)行過程责掏。
8、RACMulticastConnection :用于當(dāng)一個信號湃望,被多次訂閱時换衬,為了保證創(chuàng)建信號時,避免多次調(diào)用創(chuàng)建信號中的block证芭,造成副作用瞳浦,可以使用這個類處理。
9废士、RACScheduler: RAC中的隊列叫潦,用GCD封裝的。
- RACImmediateScheduler :立即執(zhí)行調(diào)度的任務(wù)官硝,這是唯一一個支持同步執(zhí)行的調(diào)度器矗蕊;
- RACQueueScheduler :一個抽象的隊列調(diào)度器,在一個 GCD 串行列隊中異步調(diào)度所有任務(wù)氢架;
- RACTargetQueueScheduler :繼承自 RACQueueScheduler 拔妥,在一個以一個任意的 GCD 隊列為 target 的串行隊列中異步調(diào)度所有任務(wù);
-
RACSubscriptionScheduler :一個只用來調(diào)度訂閱的調(diào)度器达箍。
以上摘錄自:
iOS ReactiveCocoa 最全常用API整理(可做為手冊查詢)
二、常見操作
1铺厨、 combineLatest:把多個信號合并成一個信號缎玫,而且需要每個信號都sendNext一次,才會觸發(fā)這個合并的信號=庾摇赃磨!
UITextField *nameTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 100, 300, 40)];
nameTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:nameTextField];
UITextField *pwdTextField = [[UITextField alloc]initWithFrame:CGRectMake(20, 140, 300, 40)];
pwdTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:pwdTextField];
UIButton *addBtn = [UIButton buttonWithType:UIButtonTypeContactAdd];
addBtn.center = self.view.center;
[self.view addSubview:addBtn];
RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
// combineLatest 把多個信號捆綁成一個信號,最多不要超過五個
// RACTuple 元組洼裤,可以像是一個字典邻辉,里面可以放多中類型
[[RACSignal combineLatest:@[nameTextField.rac_textSignal, pwdTextField.rac_textSignal ,signalBtn]] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@",x);
}];
上面監(jiān)聽了兩個文本框,一個按鈕。如果不觸發(fā)按鈕的點擊事件值骇,那么NSLog(@"%@",x);
將永遠無法打印出來莹菱,上面說了必須每個信號都sendNext一次,才會觸發(fā)這個合并的信號Vù瘛道伟!
因為是多個信號合并出一個信號,返回的值里就包含多個信號的值使碾。取值:
[[RACSignal combineLatest:@[nameTextField.rac_textSignal, pwdTextField.rac_textSignal ,signalBtn]] subscribeNext:^(RACTuple * _Nullable x) {
NSString *name = x.first;
NSString *pwd = x.second;
UIButton *btn = x.third;
NSLog(@"%@ %@ %@",name,pwd,btn);
}];
順序是按你放進去的信號順序排序的蜜徽,返回值RACTuple
叫元組,可以自己點進去看看這個東西票摇,不多做解釋了>行!
2矢门、reduce:把元祖里的值分別都取出來盆色,然后對這些值做一些操作,再合成一個值返回出去颅和。
上面這段代碼傅事,可用于登錄時的操作,監(jiān)聽兩個文本框的值峡扩,如果都有值蹭越,返回的BOOL值可以給按鈕,讓按鈕變成可點擊狀態(tài)教届。如果不滿足條件响鹃,則不可點擊!0秆怠买置!
3、 map:映射强霎,取到監(jiān)聽后的值忿项,映射成一個新值,返回出去3俏琛轩触!
[[[nameTextField rac_textSignal] map:^id _Nullable(NSString * _Nullable value) {
return @(value.length > 0);
}] subscribeNext:^(id _Nullable x) {
pwdTextField.hidden = [x boolValue];
}];
開發(fā)中,如果信號發(fā)出的值不是信號家夺,映射一般使用Map
4脱柱、 flattenMap:映射,取到信號源的值拉馋,映射成一個新的信號榨为,返回出去2液谩!
[[[nameTextField rac_textSignal] flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
value = [NSString stringWithFormat:@"數(shù)據(jù)處理: %@",value];
return [RACReturnSignal return:value];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
開發(fā)中随闺,如果信號發(fā)出的值是信號日川,映射就使用FlatternMap
5、merge:捆綁法板壮,不分先后逗鸣。
[[[nameTextField rac_textSignal] merge:[pwdTextField rac_textSignal]] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
把多個信號捆綁在一起,任何一個信號有新值都會觸發(fā)這個捆綁的信號绰精!誰觸發(fā)的信號撒璧,就拿到誰的值!笨使!
6卿樱、take:從開始一共取N次的信號
RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[signalBtn take:3] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
你點擊按鈕的前三次,都會有打印硫椰,第四次開始就不會再打印了繁调。
7、takeLast:取最后N次的信號,前提條件靶草,訂閱者必須調(diào)用完成蹄胰,因為只有完成,就知道總共有多少信號奕翔,然后取最后N次的信號TU!
RACSubject * subject = [RACSubject subject];
[[subject takeLast:1] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"one"];
[subject sendNext:@"two"];
[subject sendNext:@"three"];
[subject sendCompleted];
只會打印three
派继,取的是最后一次的信號1鐾唷!驾窟!
RACSubject
既可以作為信號庆猫,又可以發(fā)送信號!!!
8、filter:過濾信號绅络,return 滿足條件的信號月培。
[[[nameTextField rac_textSignal] filter:^BOOL(NSString * _Nullable value) {
return [value integerValue] % 2 == 0;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
輸入框內(nèi)只有你輸入滿足條件的數(shù)字才會被打印出來!6骷薄节视!
9、ignore:忽略信號假栓,忽略掉你規(guī)定的值。
[[[nameTextField rac_textSignal] ignore:@"3"] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
輸入框出現(xiàn)“3”將不被打踊舨簟X揖!0柚!內(nèi)部還是調(diào)用filter
來實現(xiàn)的牙丽。
10简卧、distinctUntilChanged:監(jiān)聽的值有明顯變化時,才會發(fā)出信號烤芦。
[[[nameTextField rac_textSignal] distinctUntilChanged] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
UI刷新的時候举娩,用的最多。
11构罗、concat:按順序拼接信號铜涉,按順序接收信號,但是必須等上一個信號完成遂唧,下一個信號才有用\酱!盖彭!
[[[nameTextField rac_textSignal] concat:[pwdTextField rac_textSignal]] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
//永遠不會打印纹烹,有關(guān)pwdTextField的值,因為前面的信號召边,沒有調(diào)用sendCompleted铺呵。
}];
下面正確使用
RACSignal *signalOne = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"下載"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"解壓"];
return nil;
}];
[[signalOne concat:signalTwo] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
//先打印下載,后打印解壓
}];
可用于兩個網(wǎng)絡(luò)請求的數(shù)據(jù)之間有依賴關(guān)系K砦酢F摇!
12贱鼻、then:也是拼接信號宴卖,一樣需要前面的信號調(diào)用sendCompleted
,才會發(fā)送信號邻悬。
RACSignal *signalOne = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"下載"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"解壓"];
return nil;
}];
[[signalOne then:^RACSignal * _Nonnull{
return signalTwo;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
然而他永遠不會打印“下載”症昏,只會打印拼接在最后的一個信號!8阜帷肝谭!
13、zipWith:把兩個信號壓縮成一個信號蛾扇,且必須兩個信號都觸發(fā)了(同次數(shù))攘烛,才會打印。兩個信號的值镀首,會合并成一個元組坟漱。
RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[[nameTextField rac_textSignal] zipWith:signalBtn] subscribeNext:^(RACTwoTuple<NSString *,id> * _Nullable x) {
NSLog(@"%@",x);
}];
輸入框觸發(fā)了三次后,點擊一下按鈕更哄,就會打印出輸入框第一次觸發(fā)的值和按鈕的值S蟪荨腥寇!當(dāng)按鈕點擊四次后,不會有打印觅捆。必須再次觸發(fā)輸入框的信號赦役,就會打印出,輸入框第四次觸發(fā)信號的值和第四次按鈕時的各種狀態(tài)栅炒。(說不清掂摔,自己去試一下吧)!S蕖乙漓!
14、takeUntil:直到某個信號觸發(fā)域携,不再監(jiān)聽簇秒。
[[[nameTextField rac_textSignal] takeUntil:signalBtn] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
點擊按鈕以后,就再也不會打印了P惚蕖G鞴邸!
15锋边、skip:跳過前面N次信號皱坛,和take相反。
RACSignal *signalBtn = [addBtn rac_signalForControlEvents:UIControlEventTouchUpInside];
[[signalBtn skip:3] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
按鈕前三次點擊無打印豆巨,第四次點擊以后剩辟,都會打印M印7妨浴!
16萍膛、switchToLatest:用來接收信號發(fā)出的信號吭服。
RACSubject *Asignal = [RACSubject subject];
RACSubject *Bsignal = [RACSubject subject];
[Asignal.switchToLatest subscribeNext:^(id x) {
//打印出 1
NSLog(@"%@",x);
}];
//A發(fā)送B
[Asignal sendNext:Bsignal];
//B發(fā)送 1
[Bsignal sendNext:@1];
只能用于信號發(fā)出的信號
17、doNext和doCompleted和doError:在發(fā)送信號前蝗罗。
[[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"chixiaodou"];
[subscriber sendCompleted];
return nil;
}] doNext:^(id _Nullable x) {
//執(zhí)行[subscriber sendNext:@"chixiaodou"]前會先走這個block
NSLog(@"doNext");
}] doCompleted:^{
//執(zhí)行[subscriber sendCompleted]前會先走這個block
NSLog(@"doCompleted");
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
doError
的栗子是一樣的艇棕,就不舉了。
18串塑、interval:多少秒執(zhí)行一次沼琉。
[[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",x);
}];
每秒都會打印現(xiàn)在的時間,要記得調(diào)用takeUntil
來結(jié)束它,不然一直打印桩匪,直到天荒地老...
[[[RACSignal interval:1 onScheduler:[RACScheduler scheduler]] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",x);
}];
控制器消失后就不再打印了
19打瘪、delay:延遲多少秒執(zhí)行。
[[signalBtn delay:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
點擊按鈕后,過2秒才打印
20瑟慈、retry:重試桃移,直到成功。
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
static int a = 1;
if (a > 3) {
[subscriber sendNext:@(a)];
}else{
[subscriber sendError:nil];
}
a++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
直到a=4
才會打印出來
21葛碧、replay:被多次訂閱后,每次都是重新執(zhí)行过吻。
__block int a = 10;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
a += 5;
[subscriber sendNext:@(a)];
return nil;
}]replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一個訂閱者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二個訂閱者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第三個訂閱者%@",x);
}];
被連續(xù)三次訂閱进泼,打印出來的值都是15,說明后面的每次訂閱a=10
O怂洹H槿啤!如果去除replay逼纸,將會打印出15洋措、20、25=芄簟菠发!加上replay后,后面的訂閱者都是從10開始算的:厣W茵!
22第喳、throttle:節(jié)流糜俗,某個時間內(nèi)只獲取最后一次的信號。
[[signalBtn throttle:3] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
如果一秒點了一百下按鈕(單身的手速)曲饱,那么再過三秒悠抹,只會打印出你第一百下點擊按鈕時的信號,前面的99次都不接收@┑怼Pǖ小!從你不點擊按鈕后算三秒R亍A呵稹!
23旺韭、RACSequence:RAC里的集合類
NSArray * arr = @[@(1), @(2), @(3), @(4), @(5)] ;
RACSequence * s1 = [arr rac_sequence];
arr = [s1 array];
可以和數(shù)組之間任意轉(zhuǎn)換
24氛谜、RACChannelTerminal:用來實現(xiàn)雙向綁定的類
RACChannelTerminal * signalnameText = [nameTextField rac_newTextChannel];
RACChannelTerminal * signalpwdText = [pwdTextField rac_newTextChannel];
[signalnameText subscribe:signalpwdText];
[signalpwdText subscribe:signalnameText];
不管怎么輸入,兩個輸入框里的內(nèi)容已經(jīng)完全保持一致了G恕V德!
25织盼、RAC(TARGET, ...):獲取某個信號的值賦給屬性
RAC(self.person,name) = nameTextField.rac_textSignal;
輸入框里的值不停的變化杨何,那么person類的name屬性值酱塔,也會不停的變化!NJ羊娃!
26、RACObserve(TARGET, KEYPATH):監(jiān)聽某個類的某個屬性
[RACObserve(self.person, name) subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
屬性的值一但改變就會打印出來0u巍H镧琛!
上面列舉的基本上是比較常用的弥雹,RAC還有非常多的功能需要自己去挖掘了垃帅,而且這些功能可以任意的組合,針對不同的業(yè)務(wù)邏輯剪勿,使用不同的組合方式贸诚。因為RAC也用了鏈?zhǔn)骄幊趟枷耄浅V`活厕吉。所以說RAC的學(xué)習(xí)曲線異常的陡峭酱固!
如果對block不太懂的,在學(xué)習(xí)RAC之前建議了解一下block赴涵!
注意:使用RAC時媒怯,牢記信號三部曲,順序不能亂K璐堋I劝!
美團是我知道使用RAC最多的APP寄纵,想要知道美團對RAC的了解有多少鳖敷,可以去美團看技術(shù)博客:傳送門