RAC使用容易忽略掉一些細節(jié)送粱,從而出現(xiàn)內存泄漏橙依,注意??
ReactiveCocoa結合了幾種編程風格:
函數(shù)式編程(Functional Programming)
響應式編程(Reactive Programming)
ReactiveCocoa被描述為函數(shù)響應式編程(FRP)框架
一、常見的類學習:
1训枢、RACSignal
/*RACSignal:有數(shù)據產生的時候就使用
使用步驟:1踩寇、創(chuàng)建信號;2藏古、訂閱信號;3忍燥、發(fā)送信號拧晕;
*/
//1、創(chuàng)建信號(冷信號)
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//有返回值的block灾前,_Nullable可為空
/*
這個block叫didSubscribe
調用:只要一個信號被訂閱就會調用
作用:發(fā)送數(shù)據
*/
NSLog(@"信號被訂閱");
//3防症、發(fā)送數(shù)據
[subscriber sendNext:@1];
return nil;
}];
//2孟辑、訂閱信號(熱信號)
[signal subscribeNext:^(id _Nullable x) {
/*
nextBlock
調用:只要訂閱者發(fā)送數(shù)據就會調用
作用:接收數(shù)據哎甲,處理數(shù)據,展示到UI上
*/
//x:信號發(fā)送的內容
NSLog(@"-----%@",x);
}];
/*
只要訂閱者調用sendNext饲嗽,就會執(zhí)行nextBlock
只要訂閱RACDynamicSignal類型的信號炭玫,就會執(zhí)行didSubscribe
前提條件:一定要是RACDynamicSignal,不同類型的信號浦楣,處理訂閱的事情不一樣
*/
2馍资、RACSubscriber
表示訂閱者的意思疗杉,用于發(fā)送信號,這是一個協(xié)議衔憨,不是一個類,只要遵守這個協(xié)議袄膏,并且實現(xiàn)方法才能成為訂閱者践图。通過create創(chuàng)建的信號,都有一個訂閱者沉馆,幫助他發(fā)送數(shù)據码党。
3、RACDisposable
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//用屬性保存下來斥黑,防止subscriber自動銷毀
_subscriber = subscriber;
[subscriber sendNext:@123];
return [RACDisposable disposableWithBlock:^{
/*
只要訂閱取消就會來到這里
作用:清空資源
*/
NSLog(@"信號被取消訂閱了");
}];
}];
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"----------%@",x);
}];
/*
默認一個信號發(fā)送完畢就會取消信號訂閱
但是只要訂閱者在揖盘,就不會自動取消信號訂閱
*/
//手動取消訂閱信號
[disposable dispose];
4、RACSubject (代替代理)
/*
RACSubject:信號提供者锌奴,自己可以充當信號兽狭,又能發(fā)送信號
想要某個類擁有多個類的功能,就可以繼承一個類,再遵守協(xié)議椭符,這叫做面向協(xié)議的思想
*/
//1荔燎、創(chuàng)建信號
RACSubject *subject = [RACSubject subject];
//2、訂閱信號
//RACSubject:僅僅保存訂閱者
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"1销钝、接收到數(shù)據:%@",x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"2有咨、接收到數(shù)據:%@",x);
}];
//3、發(fā)送數(shù)據
[subject sendNext:@123];
//底層實現(xiàn):遍歷訂閱者蒸健,調用nextBlock
5座享、RACReplaySubject (可以先發(fā)送信號再訂閱)
//1、創(chuàng)建信號
RACReplaySubject *replaySubject = [RACReplaySubject subject];
//3似忧、發(fā)送信號
[replaySubject sendNext:@1111];
//2渣叛、訂閱信號
[replaySubject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//遍歷所有的值,拿到當前訂閱者去發(fā)送數(shù)據
/*
RACReplaySubject發(fā)送數(shù)據:
1盯捌、保存值
2淳衙、遍歷所有的訂閱者,發(fā)送數(shù)據
RACReplaySubject可以先發(fā)送信號再訂閱
*/
6饺著、RACMulticastConnection
用法:當一個信號箫攀,被多次訂閱時,為了保證創(chuàng)建信號時幼衰,避免多次調用創(chuàng)建信號中的block靴跛,也就是請求數(shù)據的block,造成副作用渡嚣,可以使用這個類處理梢睛。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
eg:信號被多次訂閱的時候,會重復請求數(shù)據
代碼:
RACSignal *s0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---請求數(shù)據");
[subscriber sendNext:@"得到的數(shù)據"];
return nil;
}];
[s0 subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[s0 subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請求數(shù)據
2017-07-28 10:17:37.837 RAC_learning[1180:38354] 得到的數(shù)據
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請求數(shù)據
2017-07-28 10:17:37.838 RAC_learning[1180:38354] 得到的數(shù)據
這樣導致了多次請求數(shù)據识椰,所以用RACMulticastConnection可以實現(xiàn)不論多少次訂閱绝葡,只請求一次數(shù)據
eg:用RACMulticastConnection
//1、創(chuàng)建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---請求數(shù)據");
[subscriber sendNext:@"得到的數(shù)據"];
return nil;
}];
//2腹鹉、把信號轉換成連接類
RACMulticastConnection *connection = signal.publish;
//或者
//RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
//3藏畅、訂閱信號
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第一次獲取:%@",x);
}];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第二次獲戎终骸:%@",x);
}];
//4墓赴、連接
[connection connect];
輸出
2017-07-28 10:22:09.098 RAC_learning[1243:41311] ---請求數(shù)據
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第一次獲取:得到的數(shù)據
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第二次獲群讲t。旱玫降臄?shù)據
7诫硕、RACCommand
RAC中用于處理事件的類,可以把事件如何處理,事件中的數(shù)據如何傳遞刊侯,包裝到這個類中章办,他可以很方便的監(jiān)控事件的執(zhí)行過程。
使用場景:監(jiān)聽按鈕點擊,網絡請求
(1)==RACCommand==
//1藕届、創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//得到執(zhí)行命令傳入參數(shù)
NSLog(@"得到執(zhí)行命令傳入參數(shù)input = %@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"請求到的數(shù)據"];
return nil;
}];
}];
/*
如何拿到執(zhí)行命令中產生的數(shù)據
訂閱命令內部的信號
1.方式一:直接訂閱執(zhí)行命令返回的信號(execute方法返回RACSignal)
2.方式二:executionSignals:獲取信號源
*/
//2挪蹭、執(zhí)行命令
//方式一:直接訂閱執(zhí)行命令返回的信號(execute方法返回RACSignal) 必須在執(zhí)行命令之后執(zhí)行
/*
RACSignal *signal = [command execute:@1];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
*/
//方式二:executionSignals:獲取信號源 必須在執(zhí)行命令之前執(zhí)行
/*
[command.executionSignals subscribeNext:^(RACSignal *x) {
//這里獲取到的是RACSignal
[x subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
*/
//switchToLatest:得到信號源中最新的信號
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[command execute:@1];
(2)==switchToLatest==:得到信號源中最新的信號
// 創(chuàng)建信號中信號
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
//只會得到最新的發(fā)送的信號signalB
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 發(fā)送信號
[signalOfSignals sendNext:signalA];
[signalOfSignals sendNext:signalB];
[signalA sendNext:@1];
[signalB sendNext:@"BB"];
[signalA sendNext:@"11"];
(3)==executing==:監(jiān)聽事件有沒有完成
// 1.創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送數(shù)據
[subscriber sendNext:@"執(zhí)行命令產生的數(shù)據"];
// 主動發(fā)送完成,這樣才會監(jiān)聽到發(fā)送完成的時候
[subscriber sendCompleted];
return nil;
}];
}];
// 監(jiān)聽事件有沒有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) {
// 當前正在執(zhí)行
NSLog(@"當前正在執(zhí)行");
}else{
// 執(zhí)行完成/沒有執(zhí)行
NSLog(@"執(zhí)行完成/沒有執(zhí)行");
}
}];
// 2.執(zhí)行命令
[command execute:@1];
二休偶、集合類學習
1梁厉、RACTuple
(1)當作數(shù)組用
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"456",@789]];
NSString *string = tuple[0];
NSLog(@"%@",string);
2、RACSequence
(1)當作數(shù)組用
NSArray *array = @[@"123",@"456",@789];
//數(shù)組轉集合
RACSequence *sequence = array.rac_sequence;
//集合轉信號
RACSignal *signal = sequence.signal;
//遍歷
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//簡單寫法------------
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
(2)當集合用
NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack:用來解析元組
// 宏里面的參數(shù),傳需要解析出來的變量名
// = 右邊,放需要解析的元組
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@", key, value);
}];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]];
NSMutableArray *array = [NSMutableArray array];
[dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *dict) {
Flag *flag = [Flag flagWithDict:dict];
[array addObject:flag];
}];
//更高級點的用法
NSArray *flagArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary *dict) {
return [Flag flagWithDict:dict];
}] array];
三踏兜、開發(fā)中常見用法 (轉換成信號然后訂閱)
1词顾、代替代理:
(1)RACSubject :可以傳值
(2)rac_signalForSelector :無法傳值
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"控制器知道按鈕被點擊");
}];
2、代替KVO :
rac_valuesForKeyPath:用于監(jiān)聽某個對象的屬性改變碱妆。
[[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
// x:修改的值
NSLog(@"%@",x);
}];
3肉盹、監(jiān)聽事件:
rac_signalForControlEvents:用于監(jiān)聽某個事件。
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按鈕點擊了");
}];
4疹尾、代替通知:
rac_addObserverForName:用于監(jiān)聽某個通知上忍。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
5、監(jiān)聽文本框文字改變:
rac_textSignal:只要文本框發(fā)出改變就會發(fā)出這個信號纳本。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
6窍蓝、處理當界面有多次請求時,需要都獲取到數(shù)據時饮醇,才能展示界面
rac_liftSelector:withSignalsFromArray:
Signals:當傳入的Signals(信號數(shù)組)它抱,每一個signal都至少sendNext過一次秕豫,就會去觸發(fā)第一個selector參數(shù)的方法朴艰。
使用注意:幾個信號,參數(shù)一的方法就幾個參數(shù)混移,每個參數(shù)對應信號發(fā)出的數(shù)據祠墅。
- (void)viewDidLoad {
[super viewDidLoad];
RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//這里進行網絡請求
[subscriber sendNext:@"0000000"];
return nil;
}];
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//這里進行網絡請求
[subscriber sendNext:@"1111111"];
return nil;
}];
/*
selector方法參數(shù)個數(shù)必須與信號數(shù)組個數(shù)一致,表示獲得到的數(shù)據
rac_liftSelector:必須信號數(shù)組中的信號都發(fā)送數(shù)據才會進入selector方法中
*/
[self rac_liftSelector:@selector(updateUIWithOne:two:) withSignalsFromArray:@[signal0, signal1]];
}
- (void)updateUIWithOne:(NSString *)one two:(NSString *)two{
NSLog(@"one = %@;\ntwo = %@",one,two);
}
四歌径、常見的宏
1毁嗦、RAC(<#TARGET, ...#>):用于給某個對象的某個屬性綁定
// 監(jiān)聽文本框內容
[_textField.rac_textSignal subscribeNext:^(id x) {
_label.text = x;
}];
//使用RAC宏:
// 用來給某個對象的某個屬性綁定信號,只要產生信號內容,就會把內容給屬性賦值
RAC(_label,text) = _textField.rac_textSignal;
2、RACObserve(self, name):監(jiān)聽某個對象的某個屬性,返回的是信號
[RACObserve(self.view, frame) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
3回铛、@weakify(Obj)和@strongify(Obj),一般兩個都是配套使用,解決循環(huán)引用問題.
//在block外使用@weakify(self)狗准,在block內使用@strongify(self),可以防止block內使用self出現(xiàn)循環(huán)引用
4茵肃、RACTuplePack:把數(shù)據包裝成RACTuple(元組類)
// 包裝元組
RACTuple *tuple = RACTuplePack(@1,@2);
NSLog(@"%@",tuple[0]);
5腔长、RACTupleUnpack:把RACTuple(元組類)解包成對應的數(shù)據
NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
// RACTupleUnpack:用來解析元組
// 宏里面的參數(shù),傳需要解析出來的變量名
// = 右邊,放需要解析的元組
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@", key, value);
}];
五、常見操作方法
ReactiveCocoa操作思想
運用的是==Hook(鉤子)思想==验残,Hook是一種用于改變API(應用程序編程接口:方法)執(zhí)行結果的技術.
Hook用處:截獲API調用的技術捞附。
Hook原理:在每次調用一個API返回結果之前,先執(zhí)行你自己的方法,改變結果的輸出鸟召。
RAC開發(fā)方式:RAC中核心開發(fā)方式胆绊,也是綁定,之前的開發(fā)方式是賦值欧募,而用RAC開發(fā)压状,應該把重心放在綁定,也就是可以在創(chuàng)建一個對象的時候跟继,就綁定好以后想要做的事情何缓,而不是等賦值之后在去做事情。
列如:把數(shù)據展示到控件上还栓,之前都是重寫控件的setModel方法碌廓,用RAC就可以在一開始創(chuàng)建控件的時候,就綁定好數(shù)據剩盒。
1谷婆、核心方法bind
一般不會使用bind方法,因為比較底層
給RAC中的信號進行綁定辽聊,只要信號一發(fā)送數(shù)據纪挎,就能監(jiān)聽到,從而把發(fā)送數(shù)據改成自己想要的數(shù)據
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop){
value = [NSString stringWithFormat:@"changed:%@",value];
/*
在這里修改獲取到的數(shù)據
*/
return [RACReturnSignal return:value];
};
}];
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"數(shù)據"];
監(jiān)聽文本框的內容跟匆,并綁定
[[self.textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop){
value = [NSString stringWithFormat:@"輸出:%@",value];
return [RACReturnSignal return:value];
};
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
2异袄、ReactiveCocoa操作方法之映射(flattenMap,Map)
(1)falttenMap
//1、創(chuàng)建信號
RACSubject *subject = [RACSubject subject];
//2玛臂、綁定信號
RACSignal *bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
//這里的block只要原信號發(fā)送數(shù)據就會調用
value = [NSString stringWithFormat:@"lcy:%@",value];
return [RACReturnSignal return:value];
}];
//3烤蜕、訂閱信號
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//4、發(fā)送數(shù)據
[subject sendNext:@"hello"];
(2)map
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject map:^id _Nullable(id _Nullable value) {
//這里返回的值就是需要映射的值
return [NSString stringWithFormat:@"dashabi:%@",value];
}];
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"123123"];
[subject sendNext:@"123123123"];
3迹冤、ReactiveCocoa操作方法之組合
(1)concat
按一定順序拼接信號讽营,當多個信號發(fā)出的時候,有順序的接收信號泡徙。
==注意==:組合中第一個信號一定要調用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *concatSignal = [signalA concat:signalB];
[concatSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 16:33:57.588 RAC_learning[3169:192908] 發(fā)送A的數(shù)據
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello A
2017-07-28 16:33:57.589 RAC_learning[3169:192908] 發(fā)送B的數(shù)據
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello B
(2)then
用于連接兩個信號橱鹏,當?shù)谝粋€信號完成,才會連接then返回的信號堪藐,then會完全忽略第一個信號的數(shù)據
==注意==:組合中第一個信號一定要調用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signal = [signalA then:^RACSignal * _Nonnull{
return signalB;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 16:38:18.436 RAC_learning[3280:196164] 發(fā)送A的數(shù)據
2017-07-28 16:38:18.440 RAC_learning[3280:196164] 發(fā)送B的數(shù)據
2017-07-28 16:38:18.440 RAC_learning[3280:196164] hello B
(3)merge
把多個信號合并為一個信號莉兰,任何一個信號有新值的時候就會調用
不需要調用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
return nil;
}];
RACSignal *signal = [[signalA merge:signalB] merge:signalC];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 16:46:06.471 RAC_learning[3563:202620] 發(fā)送A的數(shù)據
2017-07-28 16:46:06.471 RAC_learning[3563:202620] hello A
2017-07-28 16:46:06.471 RAC_learning[3563:202620] 發(fā)送B的數(shù)據
2017-07-28 16:46:06.472 RAC_learning[3563:202620] hello B
(4)zipWith
把兩個信號壓縮成一個信號,只有當兩個信號同時發(fā)出信號內容時礁竞,并且把兩個信號的內容合并成一個==元組==(RACTuple)糖荒,才會觸發(fā)壓縮流的next事件
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signal = [signalA zipWith:signalB];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 16:52:44.200 RAC_learning[3630:205690] 發(fā)送A的數(shù)據
2017-07-28 16:52:44.201 RAC_learning[3630:205690] 發(fā)送B的數(shù)據
2017-07-28 16:52:44.204 RAC_learning[3630:205690] <RACTwoTuple: 0x6000000173b0> (
"hello A",
"hello B"
)
(5)combineLatest
將多個信號合并起來,并且拿到各個信號的最新的值,必須每個合并的signal至少都有過一次sendNext苏章,才會觸發(fā)合并的信號
(6)reduce
用于信號發(fā)出的內容是元組寂嘉,把信號發(fā)出元組的值聚合成一個值
RACSignal *signal = [RACSignal combineLatest:@[self.nameTF.rac_textSignal, self.passwordTF.rac_textSignal] reduce:^id _Nullable(NSString *name, NSString *password){
NSLog(@"%@ ooooo %@",name, password);
return @(name.length && password.length);
}];
// [signal subscribeNext:^(id _Nullable x) {
// NSLog(@"得到的數(shù)據:%@",x);
// }];
//使登錄按鈕在用戶名和密碼框都有數(shù)據的時候才會調用
RAC(self.loginButton, enabled) = signal;
4奏瞬、ReactiveCocoa操作方法之過濾
(1)filter
過濾信號,使用它可以獲取滿足條件的信號
RACSignal *signal = [self.nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
//表示當文本框輸入的長度超過六位的時候
return value.length > 6;
}];
[signal subscribeNext:^(id _Nullable x) {
//只有滿足條件的時候才會進入這個block
NSLog(@"%@",x);
}];
(2)ignore
忽略完某些值的信號.
[[self.nameTF.rac_textSignal ignore:@"000"] subscribeNext:^(NSString * _Nullable x) {
//忽略了字符串是000的值
NSLog(@"%@",x);
}];
(3)distinctUntilChanged
當上一次的值和當前的值有明顯的變化就會發(fā)出信號泉孩,否則會被忽略掉
[[self.nameTF.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
(4)take
從開始一共取N次的信號
[[self.nameTF.rac_textSignal take:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
// 1硼端、創(chuàng)建信號
RACSubject *signal = [RACSubject subject];
// 2、處理信號寓搬,訂閱信號
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.發(fā)送信號
[signal sendNext:@1];
[signal sendNext:@2];
(5)takeLast
取最后N次的信號
==前提條件==:訂閱者必須調用完成珍昨,因為只有完成,就知道總共有多少信號
==注意==:一定要調用sendComplete句喷,不然訂閱者不知道有多少
RACSubject *subject = [RACSubject subject];
[[subject takeLast:3] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
[subject sendNext:@4];
[subject sendNext:@5];
[subject sendCompleted];
(6)takeUntil
獲取信號直到執(zhí)行完這個信號
RACSubject *subject = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[subject takeUntil:signal] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@1];
[subject sendNext:@2];
/*
sendNext或者sendComplete都可以截止
sendError不可以
*/
[signal sendCompleted];
[subject sendNext:@3];
[subject sendNext:@4];
[subject sendNext:@5];
[subject sendCompleted];
// 監(jiān)聽文本框的改變镣典,直到當前對象被銷毀
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
(7)skip:(NSUInteger)
跳過幾個信號,不接受
[[self.nameTF.rac_textSignal skip:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
5、ReactiveCocoa操作方法之秩序
doNext: 執(zhí)行Next之前唾琼,會先執(zhí)行這個Block
doCompleted: 執(zhí)行sendCompleted之前兄春,會先執(zhí)行這個Block
[[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"hahaha"];
[subscriber sendCompleted];
return nil;
}] doNext:^(id _Nullable x) {
NSLog(@"doNext");
}] doCompleted:^{
NSLog(@"doComplete");
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
輸出:
2017-07-28 18:12:56.704 RAC_learning[5256:261194] doNext
2017-07-28 18:12:56.705 RAC_learning[5256:261194] hahaha
2017-07-28 18:12:56.705 RAC_learning[5256:261194] doComplete
6、ReactiveCocoa操作方法之線程
deliverOn: 內容傳遞切換到制定線程中锡溯,副作用在原來線程中,把在創(chuàng)建信號時block中的代碼稱之為副作用赶舆。
subscribeOn: 內容傳遞和副作用都會切換到制定線程中。
7祭饭、ReactiveCocoa操作方法之時間
(1)timeout
超時芜茵,可以讓一個信號在一定的時間后,自動報錯
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
return nil;
}] timeout:1 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
// 1秒后會自動調用
NSLog(@"%@",error);
}];
(2)interval
定時倡蝙,每隔一段時間發(fā)出信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"123123123"];
return nil;
}];
[[RACSignal interval:2.0 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",x);
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
(3)delay
延遲發(fā)送next
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"123123123"];
return nil;
}] delay:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
8九串、ReactiveCocoa操作方法之重復
(1)retry重試
只要失敗,就會重新執(zhí)行創(chuàng)建信號中的block,直到成功.
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@1];
}else{
NSLog(@"接收到錯誤");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
(2)replay重放
當一個信號被多次訂閱,反復播放內容
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//只會進入這個block一次寺鸥,不會反復進入
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一個訂閱者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二個訂閱者%@",x);
}];
(3)throttle節(jié)流
當某個信號發(fā)送比較頻繁時猪钮,可以使用節(jié)流,在某一段時間不發(fā)送信號內容析既,過了一段時間獲取信號的最新內容發(fā)出躬贡。
R
ACSubject *signal = [RACSubject subject];
_signal = signal;
// 節(jié)流谆奥,在一定時間(1秒)內眼坏,不接收任何信號內容,過了這個時間(1秒)獲取最后發(fā)送的信號內容發(fā)出酸些。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];