序
之前就一直在看ReactiveCocoa 相關(guān)知識(shí) 但是有感覺(jué)每次看完收貨甚微窖逗,且感覺(jué)零零散散 岩喷,本blog 僅僅是記錄自己的學(xué)習(xí)過(guò)程
文章目錄
- 1 ReactiveCocoa 核心方法Bind
- 2 ReactiveCocoa 之映射(flattenMap涵防,Map)
- 2-1 flattenMap和Map的區(qū)別
- 3 ReactiveCocoa 操作方法之組合
- 3-1 concat 按順序的接受信號(hào)
- 3-2 then 用于連接兩個(gè)信號(hào) 當(dāng)?shù)谝粋€(gè)信號(hào)完成 才會(huì)連接then返回的信號(hào)
- 3-3 merge 把多個(gè)信號(hào)合并成一個(gè)信號(hào) 任何一個(gè)信號(hào)有新值的時(shí)候就會(huì)調(diào)用
- 3-4 zipWith 把兩個(gè)信號(hào)壓縮成一個(gè)信號(hào) 只有當(dāng)兩個(gè)信號(hào)同時(shí)發(fā)出信號(hào)內(nèi)容時(shí) 并且把兩個(gè)信號(hào)的內(nèi)容合并成一個(gè)元祖 才會(huì)觸發(fā)壓縮流的next事件
- 3-5 combineLatest 將多個(gè)信號(hào)合并起來(lái) 并且拿到各個(gè)信號(hào)的最新的值 必須每個(gè)合并的signal至少都有過(guò)一次sendNext 才會(huì)觸發(fā)合并的信號(hào) 和zipwith 差不多
- 3-6 reduce(減少,降低 覆山,歸納) 聚合 用于信號(hào)發(fā)出的內(nèi)容是元祖 把信號(hào)發(fā)出元祖的值聚合成一個(gè)值 然后通過(guò)reduce返回出來(lái)
- 4 ReactiveCocoa 操作方法之過(guò)濾
- 4-1 filter: 過(guò)濾信號(hào) 使用他可以獲取滿(mǎn)足條件的信號(hào)
- 4-2 ignore 忽略某些值 的信號(hào)
- 4-3 distinctUntilChanged 當(dāng)上一次的值和當(dāng)前的值不一樣才會(huì)發(fā)出信號(hào) 如果兩次的值一樣 就不會(huì)發(fā)出信號(hào)
- 4-4 take 取出信號(hào) 取出前幾個(gè)信號(hào)
- 4-5 takeLast 取最后N次的信號(hào) 前提條件訂閱者必須調(diào)用完成 因?yàn)橹挥型瓿刹胖揽偣灿卸嗌賯€(gè)信號(hào)
- 4-6 takeUntil(RACSignal *)獲取信號(hào)直到某個(gè)信號(hào)執(zhí)行完成
- 4-7 skip:(NSUInteger):跳過(guò)幾個(gè)信號(hào) 不接收
- 5 ReactiveCocoa 操作方法之秩序
- 5-1 doNext 執(zhí)行next之前會(huì)先執(zhí)行這個(gè)block
- 5-2 doComplete 執(zhí)行sendComplete就會(huì)調(diào)用這個(gè)方法
- 6 ReactiveCocoa 操作方法之時(shí)間
- timeout: 超時(shí) 可以讓一個(gè)信號(hào)在一定的時(shí)間后 自動(dòng)報(bào)錯(cuò)
- interval: 定時(shí) 每隔一段時(shí)間就發(fā)出信號(hào)
- delay 延遲發(fā)送next
- 7 ReactiveCocoa 操作方法之重復(fù)
- retry 重試 只要失敗 就一直執(zhí)行信號(hào)中的block 直到成功
- replay 重放 當(dāng)一個(gè)信號(hào)被多次訂閱 反復(fù)播放內(nèi)容(沒(méi)什么卵用)
一 ReactiveCocoa常見(jiàn)操作方法介紹
1.1 ReactiveCocoa 核心方法Bind
ReactiveCocoa操作的核心方法是bind(綁定),而且RAC中核心開(kāi)發(fā)方式京革,也是綁定,之前的開(kāi)發(fā)方式是賦值辫樱,而用RAC開(kāi)發(fā)峭拘,應(yīng)該把重心放在綁定,也就是可以在創(chuàng)建一個(gè)對(duì)象的時(shí)候狮暑,就綁定好以后想要做的事情鸡挠,而不是等賦值之后在去做事情。
列如:把數(shù)據(jù)展示到控件上搬男,之前都是重寫(xiě)控件的setModel方法拣展,用RAC就可以在一開(kāi)始創(chuàng)建控件的時(shí)候,就綁定好數(shù)據(jù)缔逛。
在開(kāi)發(fā)中很少使用bind方法备埃,bind屬于RAC中的底層方法,RAC已經(jīng)封裝了很多好用的其他方法褐奴,底層都是調(diào)用bind按脚,用法比bind簡(jiǎn)單.
bind 方法簡(jiǎn)單的介紹和使用
// 拼接內(nèi)容
// 方式一 拿到結(jié)果后拼接內(nèi)容
[self.textFiled.rac_textSignal subscribeNext:^(id x) {
NSLog(@"內(nèi)容:%@",x);
}];
// 方式二 拿到結(jié)果之前 進(jìn)行拼接 利用Bind方法處理
// 處理原有信號(hào) 對(duì)信號(hào)進(jìn)行加工
// bind 方法參數(shù) 需要傳入一個(gè)返回值是 RACStreamBindBlock 的參數(shù)
// RACStreamBindBlock 是一個(gè)block類(lèi)型 返回值是信號(hào) 參數(shù)是value和stop 因此參數(shù)block返回值也是一個(gè)block
// RACStreamBindBlock
// value 表示接收到信號(hào)的原始值 還沒(méi)做處理
// *stop 用來(lái)控制綁定block 如果 *stop = yes 那么就會(huì)結(jié)束綁定
// 返回值: 信號(hào) 做好處理 在通過(guò)這個(gè)信號(hào)返回出去 一般使用RACreturnsignal,需要手動(dòng)導(dǎo)入頭文件RACReturnSignal.h
// bind方法使用步驟:
// 1 傳入一個(gè)返回值為 RACStreamBindBlock 的bindblock
// 2 描述一個(gè)RACStreamBindBlock 類(lèi)型的bindblock作為block的返回值
// 3 描述一個(gè)返回結(jié)果的信號(hào) 作為bindblock的返回值
// 在bindblock中做信號(hào)結(jié)果的處理
// 底層實(shí)現(xiàn):
// 1 源信號(hào)調(diào)用bind,會(huì)重新創(chuàng)建一個(gè)綁定信號(hào)歉糜。
// 2 當(dāng)綁定信號(hào)被訂閱乘寒,就會(huì)調(diào)用綁定信號(hào)中的didSubscribe,生成一個(gè)bindingBlock匪补。
// 3 當(dāng)源信號(hào)有內(nèi)容發(fā)出伞辛,就會(huì)把內(nèi)容傳遞到bindingBlock處理,調(diào)用bindingBlock(value,stop)
// 4 調(diào)用bindingBlock(value,stop)夯缺,會(huì)返回一個(gè)內(nèi)容處理完成的信號(hào)(RACReturnSignal)蚤氏。
// 5 訂閱RACReturnSignal,就會(huì)拿到綁定信號(hào)的訂閱者踊兜,把處理完成的信號(hào)內(nèi)容發(fā)送出來(lái)竿滨。
[[self.textFiled.rac_textSignal bind:^RACStreamBindBlock{
return ^RACStream *(id value,BOOL *stop){
return [RACReturnSignal return:[NSString stringWithFormat:@"輸出%@",value]];
};
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.2 映射(flattenMap,Map)
- 這兩者主要是把源信號(hào) 內(nèi)容映射成新的內(nèi)容
---- flattenMap : 把原信號(hào)的內(nèi)容映射成一個(gè)新信號(hào) 信號(hào)可以是任意的類(lèi)型
// flattenMap使用步驟:
// 1.傳入一個(gè)block,block類(lèi)型是返回值RACStream于游,參數(shù)value
// 2.參數(shù)value就是源信號(hào)的內(nèi)容毁葱,拿到源信號(hào)的內(nèi)容做處理
// 3.包裝成RACReturnSignal信號(hào),返回出去贰剥。
[[self.textFiled.rac_textSignal flattenMap:^RACStream *(id value) {
// 原信號(hào)發(fā)出的時(shí)候就會(huì)調(diào)用block
// block作用 : 改變?cè)盘?hào)的內(nèi)容
// 返回值 綁定信號(hào)的內(nèi)容
return [RACReturnSignal return:[NSString stringWithFormat:@"內(nèi)容%@",value]];
}]subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
---- map: 把原信號(hào)的值映射成一個(gè)新值
// map 的使用步驟
// 1 傳入一個(gè)block 類(lèi)型是返回對(duì)象 參數(shù)是value
// 2 value就是原信號(hào)的內(nèi)容 直接拿到原信號(hào)的內(nèi)容做處理
// 3 吧處理好的內(nèi)容直接返回就好了 不用包裝成信號(hào) 返回的值就是映射的值
[[self.textFiled.rac_textSignal map:^id(id value) {
return [NSString stringWithFormat:@"內(nèi)容:%@",value];
}]subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
FlatternMap 和 Map的區(qū)別
1 FlatternMap 中的block返回的是信號(hào)
2 Map中的block返回對(duì)象
3 開(kāi)發(fā)中倾剿,如果信號(hào)發(fā)出的值不是信號(hào) 映射一般使用Map
4 開(kāi)發(fā)中 如果信號(hào)發(fā)出的是信號(hào) 映射一般使用FlatternMap
signalOfSignals 信號(hào)的信號(hào) 用FlatternMap
RACSubject *signalOfsignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[signalOfsignals flattenMap:^RACStream *(id value) {
// 當(dāng)signalOfsignal 的signal發(fā)發(fā)出信號(hào)才會(huì)調(diào)用
NSLog(@"攔截%@",value);
return value;
}] subscribeNext:^(id x) {
NSLog(@"內(nèi)容%@",x);
}];
// 信號(hào)的信號(hào)發(fā)送信號(hào)
[signalOfsignals sendNext:signal];
[signal sendNext:@"奧卡姆剃須刀"];
1.3 ReactiveCocoa 操作方法值組合
-
concat 按一定順序拼接信號(hào) 當(dāng)多個(gè)信號(hào)發(fā)出的時(shí)候有順序的接受信號(hào)
// 按一定順序拼接信號(hào) 當(dāng)多個(gè)信號(hào)發(fā)出的時(shí)候有順序的接受信號(hào)
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是一號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是二號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *concatSignal = [signal2 concat:signal1];
// 只有第一個(gè)信號(hào)完成后 才會(huì)執(zhí)行第二個(gè)信號(hào)
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
then 用于連接兩個(gè)信號(hào) 當(dāng)?shù)谝粋€(gè)信號(hào)完成 才會(huì)連接then返回的信號(hào)
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是信號(hào)"];
// 只有當(dāng)?shù)谝粋€(gè)信號(hào)完成后 第二個(gè)信號(hào)才會(huì)執(zhí)行
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [oneSignal then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第二個(gè)的信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
}];
// 訂閱第一個(gè)信號(hào)
[oneSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 訂閱第二個(gè)信號(hào) 只有第一個(gè)信號(hào)完成后 第二個(gè)信號(hào)發(fā)揮被觸發(fā)
[twoSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
merge 把多個(gè)信號(hào)合并成一個(gè)信號(hào) 任何一個(gè)信號(hào)有新值的時(shí)候就會(huì)調(diào)用
// 底層實(shí)現(xiàn):
// 1.合并信號(hào)被訂閱的時(shí)候,就會(huì)遍歷所有信號(hào)蚌成,并且發(fā)出這些信號(hào)前痘。
// 2.每發(fā)出一個(gè)信號(hào),這個(gè)信號(hào)就會(huì)被訂閱
// 3.也就是合并信號(hào)一被訂閱担忧,就會(huì)訂閱里面所有的信號(hào)芹缔。
// 4.只要有一個(gè)信號(hào)被發(fā)出就會(huì)被監(jiān)聽(tīng)。
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第一個(gè)信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第二個(gè)的信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *mergeSignal = [oneSignal merge:twoSignal];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
zipWith 把兩個(gè)信號(hào)壓縮成一個(gè)信號(hào) 只有當(dāng)兩個(gè)信號(hào)同時(shí)發(fā)出信號(hào)內(nèi)容時(shí) 并且把兩個(gè)信號(hào)的內(nèi)容合并成一個(gè)元祖 才會(huì)觸發(fā)壓縮流的next事件
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第一個(gè)信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第二個(gè)的信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *zipSignal = [oneSignal zipWith:twoSignal];
// 合并出來(lái)是元祖 要想拿到元祖 要對(duì)元祖進(jìn)行解包
[zipSignal subscribeNext:^(id x) {
RACTupleUnpack(id data1,id data2) = x;
NSLog(@"%@---%@",data1,data2);
}];
-
combineLatest 將多個(gè)信號(hào)合并起來(lái) 并且拿到各個(gè)信號(hào)的最新的值 必須每個(gè)合并的signal至少都有過(guò)一次sendNext 才會(huì)觸發(fā)合并的信號(hào) 和zipwith 差不多
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第一個(gè)信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第二個(gè)的信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
// 必須兩個(gè)都發(fā)信號(hào) 才會(huì)觸發(fā)合并信號(hào) 和zipWith 一樣沒(méi)什么區(qū)別 也是會(huì)組裝成元祖
RACSignal *combineSignal = [oneSignal combineLatestWith:twoSignal];
[combineSignal subscribeNext:^(id x) {
RACTupleUnpack(id data1,id data2) = x;
NSLog(@"%@--%@",data1,data2);
}];
-
reduce(減少瓶盛,降低 最欠,歸納) 聚合 用于信號(hào)發(fā)出的內(nèi)容是元祖 把信號(hào)發(fā)出元祖的值聚合成一個(gè)值 然后通過(guò)reduce返回出來(lái)
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第一個(gè)信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是第二個(gè)的信號(hào)"];
[subscriber sendCompleted];
return nil;
}];
// 聚合
// 常見(jiàn)的用法 (先組合在聚合)
// combineLatee里邊有多少個(gè)參數(shù)組合 后邊的reduce就應(yīng)該有多少個(gè)參數(shù)
// reduce 返回值是聚合之后的內(nèi)容
RACSignal *reduceSignal = [RACSignal combineLatest:@[oneSignal,twoSignal] reduce:^id(NSString *data1,NSString *data2){
return [NSString stringWithFormat:@"我是數(shù)據(jù)一%@---我是數(shù)據(jù)二%@",data1,data2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.4 ReactiveCocoa 操作方法之過(guò)濾
-
filter: 過(guò)濾信號(hào) 使用他可以獲取滿(mǎn)足條件的信號(hào)
RACSignal *newSignal = [self.textFiled.rac_textSignal filter:^BOOL(NSString * value) {
return value.length > 3;
}];
// 只有長(zhǎng)度大于三的字符串才能被打印粗來(lái)
[newSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
ignore 忽略某些值 的信號(hào)
// 只能忽略相等的值 其他的都忽略不了 內(nèi)部調(diào)用的是filter過(guò)濾
[[self.textFiled.rac_textSignal ignore:@"123"] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
distinctUntilChanged 當(dāng)上一次的值和當(dāng)前的值不一樣才會(huì)發(fā)出信號(hào) 如果兩次的值一樣 就不會(huì)發(fā)出信號(hào)
// 只有兩次數(shù)據(jù)不一樣才會(huì)觸發(fā)信號(hào)
[[_textFiled.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
take 取出信號(hào) 取出前幾個(gè)信號(hào)
// 1 創(chuàng)建信號(hào)
RACSubject *signal = [RACSubject subject];
// 2 處理信號(hào) 訂閱信號(hào)的個(gè)數(shù) 如果訂閱一個(gè) 只會(huì)接受第一個(gè)信號(hào) subject 可以先訂閱信號(hào) 在發(fā)送信號(hào)
[[signal take:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"1"];
[signal sendNext:@"2"];
-
takeLast 取最后N次的信號(hào) 前提條件訂閱者必須調(diào)用完成 因?yàn)橹挥型瓿刹胖揽偣灿卸嗌賯€(gè)信號(hào)
RACSubject *signal = [RACSubject subject];
// 取最后n次的信號(hào)
[[signal takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"1"];
[signal sendNext:@"2"];
[signal sendNext:@"3"];
[signal sendNext:@"4"];
// 必須調(diào)用完成 只用調(diào)用完成才能知道總共的信號(hào)量
[signal sendCompleted];
-
takeUntil(RACSignal *)獲取信號(hào)直到某個(gè)信號(hào)執(zhí)行完成
// 創(chuàng)建一個(gè)信號(hào)
RACSignal *deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)];
// 當(dāng)deallocSignal信號(hào)發(fā)送的時(shí)候 就會(huì)移除通知
[[[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardWillShowNotification object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) {
NSLog(@"鍵盤(pán)彈出%@",x);
}];
-
skip:(NSUInteger):跳過(guò)幾個(gè)信號(hào) 不接收
RACSubject *signal = [RACSubject subject];
// 只會(huì)接收第二個(gè)信號(hào)
[[signal skip:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"我是信號(hào)一"];
[signal sendNext:@"我是信號(hào)二"];
1.5 ReactiveCocoa 操作方法之秩序
-
doNext 執(zhí)行next之前會(huì)先執(zhí)行這個(gè)block
-
doComplete 執(zhí)行sendComplete就會(huì)調(diào)用這個(gè)方法
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"我是奧卡姆剃須刀"];
[subscriber sendCompleted];
return nil;
// 在執(zhí)行訂閱信號(hào)之前 會(huì)先執(zhí)行這個(gè)方法
}]doNext:^(id x) {
NSLog(@"doNext--%@",x);
// 信號(hào)完成后會(huì)調(diào)用這個(gè)方法
}]doCompleted:^{
NSLog(@"完成");
// 訂閱信號(hào)
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.6 ReactiveCocoa 操作方法之時(shí)間
-
timeout: 超時(shí) 可以讓一個(gè)信號(hào)在一定的時(shí)間后 自動(dòng)報(bào)錯(cuò)
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"123"];
return nil;
// 報(bào)錯(cuò)的時(shí)間是3秒
}] timeout:3 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"subscribeNext-%@",x);
// 3秒后 自動(dòng)報(bào)錯(cuò)
} error:^(NSError *error) {
NSLog(@"error-%@",error);
}];
-
interval: 定時(shí) 每隔一段時(shí)間就發(fā)出信號(hào)
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
delay 延遲發(fā)送next
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"延遲兩秒鐘"];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.7 ReactiveCocoa 操作方法之重復(fù)
-
retry 重試 只要失敗 就一直執(zhí)行信號(hào)中的block 直到成功
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@"123"];
}else{
[subscriber sendError:nil];
}
i++;
return nil;
}] retry ] subscribeNext:^(id x) {
NSLog(@"subscribeNext--%@",x);
}error:^(NSError *error) {
NSLog(@"error--%@",error);
}];
-
replay 重放 當(dāng)一個(gè)信號(hào)被多次訂閱 反復(fù)播放內(nèi)容(沒(méi)什么卵用)
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"123"];
[subscriber sendNext:@"456"];
return nil;
}]replay];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];