RAC使用容易忽略掉一些細(xì)節(jié),從而出現(xiàn)內(nèi)存泄漏,注意??
ReactiveCocoa結(jié)合了幾種編程風(fēng)格:
函數(shù)式編程(Functional Programming)
響應(yīng)式編程(Reactive Programming)
ReactiveCocoa被描述為函數(shù)響應(yīng)式編程(FRP)框架
一、常見的類學(xué)習(xí):
1、RACSignal
/*RACSignal:有數(shù)據(jù)產(chǎn)生的時(shí)候就使用
使用步驟:1、創(chuàng)建信號(hào);2、訂閱信號(hào);3、發(fā)送信號(hào);
*/
//1、創(chuàng)建信號(hào)(冷信號(hào))
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//有返回值的block,_Nullable可為空
/*
這個(gè)block叫didSubscribe
調(diào)用:只要一個(gè)信號(hào)被訂閱就會(huì)調(diào)用
作用:發(fā)送數(shù)據(jù)
*/
NSLog(@"信號(hào)被訂閱");
//3、發(fā)送數(shù)據(jù)
[subscriber sendNext:@1];
return nil;
}];
//2、訂閱信號(hào)(熱信號(hào))
[signal subscribeNext:^(id _Nullable x) {
/*
nextBlock
調(diào)用:只要訂閱者發(fā)送數(shù)據(jù)就會(huì)調(diào)用
作用:接收數(shù)據(jù),處理數(shù)據(jù),展示到UI上
*/
//x:信號(hào)發(fā)送的內(nèi)容
NSLog(@"-----%@",x);
}];
/*
只要訂閱者調(diào)用sendNext,就會(huì)執(zhí)行nextBlock
只要訂閱RACDynamicSignal類型的信號(hào),就會(huì)執(zhí)行didSubscribe
前提條件:一定要是RACDynamicSignal,不同類型的信號(hào),處理訂閱的事情不一樣
*/
2、RACSubscriber
表示訂閱者的意思,用于發(fā)送信號(hào),這是一個(gè)協(xié)議,不是一個(gè)類,只要遵守這個(gè)協(xié)議,并且實(shí)現(xiàn)方法才能成為訂閱者。通過create創(chuàng)建的信號(hào),都有一個(gè)訂閱者,幫助他發(fā)送數(shù)據(jù)。
3、RACDisposable
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//用屬性保存下來,防止subscriber自動(dòng)銷毀
_subscriber = subscriber;
[subscriber sendNext:@123];
return [RACDisposable disposableWithBlock:^{
/*
只要訂閱取消就會(huì)來到這里
作用:清空資源
*/
NSLog(@"信號(hào)被取消訂閱了");
}];
}];
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"----------%@",x);
}];
/*
默認(rèn)一個(gè)信號(hào)發(fā)送完畢就會(huì)取消信號(hào)訂閱
但是只要訂閱者在,就不會(huì)自動(dòng)取消信號(hào)訂閱
*/
//手動(dòng)取消訂閱信號(hào)
[disposable dispose];
4、RACSubject (代替代理)
/*
RACSubject:信號(hào)提供者,自己可以充當(dāng)信號(hào),又能發(fā)送信號(hào)
想要某個(gè)類擁有多個(gè)類的功能,就可以繼承一個(gè)類,再遵守協(xié)議,這叫做面向協(xié)議的思想
*/
//1、創(chuàng)建信號(hào)
RACSubject *subject = [RACSubject subject];
//2、訂閱信號(hào)
//RACSubject:僅僅保存訂閱者
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"1、接收到數(shù)據(jù):%@",x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"2、接收到數(shù)據(jù):%@",x);
}];
//3、發(fā)送數(shù)據(jù)
[subject sendNext:@123];
//底層實(shí)現(xiàn):遍歷訂閱者,調(diào)用nextBlock
5、RACReplaySubject (可以先發(fā)送信號(hào)再訂閱)
//1、創(chuàng)建信號(hào)
RACReplaySubject *replaySubject = [RACReplaySubject subject];
//3、發(fā)送信號(hào)
[replaySubject sendNext:@1111];
//2、訂閱信號(hào)
[replaySubject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//遍歷所有的值,拿到當(dāng)前訂閱者去發(fā)送數(shù)據(jù)
/*
RACReplaySubject發(fā)送數(shù)據(jù):
1、保存值
2、遍歷所有的訂閱者,發(fā)送數(shù)據(jù)
RACReplaySubject可以先發(fā)送信號(hào)再訂閱
*/
6、RACMulticastConnection
用法:當(dāng)一個(gè)信號(hào),被多次訂閱時(shí),為了保證創(chuàng)建信號(hào)時(shí),避免多次調(diào)用創(chuàng)建信號(hào)中的block,也就是請(qǐng)求數(shù)據(jù)的block,造成副作用,可以使用這個(gè)類處理。
使用注意:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創(chuàng)建.
eg:信號(hào)被多次訂閱的時(shí)候,會(huì)重復(fù)請(qǐng)求數(shù)據(jù)
代碼:
RACSignal *s0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---請(qǐng)求數(shù)據(jù)");
[subscriber sendNext:@"得到的數(shù)據(jù)"];
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] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:17:37.837 RAC_learning[1180:38354] 得到的數(shù)據(jù)
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:17:37.838 RAC_learning[1180:38354] 得到的數(shù)據(jù)
這樣導(dǎo)致了多次請(qǐng)求數(shù)據(jù),所以用RACMulticastConnection可以實(shí)現(xiàn)不論多少次訂閱,只請(qǐng)求一次數(shù)據(jù)
eg:用RACMulticastConnection
//1、創(chuàng)建信號(hào)
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---請(qǐng)求數(shù)據(jù)");
[subscriber sendNext:@"得到的數(shù)據(jù)"];
return nil;
}];
//2、把信號(hào)轉(zhuǎn)換成連接類
RACMulticastConnection *connection = signal.publish;
//或者
//RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
//3、訂閱信號(hào)
[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] ---請(qǐng)求數(shù)據(jù)
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第一次獲?。旱玫降臄?shù)據(jù)
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第二次獲?。旱玫降臄?shù)據(jù)
7、RACCommand
RAC中用于處理事件的類,可以把事件如何處理,事件中的數(shù)據(jù)如何傳遞,包裝到這個(gè)類中,他可以很方便的監(jiān)控事件的執(zhí)行過程。
使用場(chǎng)景:監(jiān)聽按鈕點(diǎn)擊,網(wǎng)絡(luò)請(qǐng)求
(1)==RACCommand==
//1、創(chuàng)建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//得到執(zhí)行命令傳入?yún)?shù)
NSLog(@"得到執(zhí)行命令傳入?yún)?shù)input = %@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"請(qǐng)求到的數(shù)據(jù)"];
return nil;
}];
}];
/*
如何拿到執(zhí)行命令中產(chǎn)生的數(shù)據(jù)
訂閱命令內(nèi)部的信號(hào)
1.方式一:直接訂閱執(zhí)行命令返回的信號(hào)(execute方法返回RACSignal)
2.方式二:executionSignals:獲取信號(hào)源
*/
//2、執(zhí)行命令
//方式一:直接訂閱執(zhí)行命令返回的信號(hào)(execute方法返回RACSignal) 必須在執(zhí)行命令之后執(zhí)行
/*
RACSignal *signal = [command execute:@1];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
*/
//方式二:executionSignals:獲取信號(hào)源 必須在執(zhí)行命令之前執(zhí)行
/*
[command.executionSignals subscribeNext:^(RACSignal *x) {
//這里獲取到的是RACSignal
[x subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
*/
//switchToLatest:得到信號(hào)源中最新的信號(hào)
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[command execute:@1];
(2)==switchToLatest==:得到信號(hào)源中最新的信號(hào)
// 創(chuàng)建信號(hào)中信號(hào)
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
//只會(huì)得到最新的發(fā)送的信號(hào)signalB
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 發(fā)送信號(hào)
[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ù)據(jù)
[subscriber sendNext:@"執(zhí)行命令產(chǎn)生的數(shù)據(jù)"];
// 主動(dòng)發(fā)送完成,這樣才會(huì)監(jiān)聽到發(fā)送完成的時(shí)候
[subscriber sendCompleted];
return nil;
}];
}];
// 監(jiān)聽事件有沒有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) {
// 當(dāng)前正在執(zhí)行
NSLog(@"當(dāng)前正在執(zhí)行");
}else{
// 執(zhí)行完成/沒有執(zhí)行
NSLog(@"執(zhí)行完成/沒有執(zhí)行");
}
}];
// 2.執(zhí)行命令
[command execute:@1];
二、集合類學(xué)習(xí)
1、RACTuple
(1)當(dāng)作數(shù)組用
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"456",@789]];
NSString *string = tuple[0];
NSLog(@"%@",string);
2、RACSequence
(1)當(dāng)作數(shù)組用
NSArray *array = @[@"123",@"456",@789];
//數(shù)組轉(zhuǎn)集合
RACSequence *sequence = array.rac_sequence;
//集合轉(zhuǎn)信號(hào)
RACSignal *signal = sequence.signal;
//遍歷
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//簡單寫法------------
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
(2)當(dāng)集合用
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];
}];
//更高級(jí)點(diǎn)的用法
NSArray *flagArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary *dict) {
return [Flag flagWithDict:dict];
}] array];
三、開發(fā)中常見用法 (轉(zhuǎn)換成信號(hào)然后訂閱)
1、代替代理:
(1)RACSubject :可以傳值
(2)rac_signalForSelector :無法傳值
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"控制器知道按鈕被點(diǎn)擊");
}];
2、代替KVO :
rac_valuesForKeyPath:用于監(jiān)聽某個(gè)對(duì)象的屬性改變。
[[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
// x:修改的值
NSLog(@"%@",x);
}];
3、監(jiān)聽事件:
rac_signalForControlEvents:用于監(jiān)聽某個(gè)事件。
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按鈕點(diǎn)擊了");
}];
4、代替通知:
rac_addObserverForName:用于監(jiān)聽某個(gè)通知。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
5、監(jiān)聽文本框文字改變:
rac_textSignal:只要文本框發(fā)出改變就會(huì)發(fā)出這個(gè)信號(hào)。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
6、處理當(dāng)界面有多次請(qǐng)求時(shí),需要都獲取到數(shù)據(jù)時(shí),才能展示界面
rac_liftSelector:withSignalsFromArray:
Signals:當(dāng)傳入的Signals(信號(hào)數(shù)組),每一個(gè)signal都至少sendNext過一次,就會(huì)去觸發(fā)第一個(gè)selector參數(shù)的方法。
使用注意:幾個(gè)信號(hào),參數(shù)一的方法就幾個(gè)參數(shù),每個(gè)參數(shù)對(duì)應(yīng)信號(hào)發(fā)出的數(shù)據(jù)。
- (void)viewDidLoad {
[super viewDidLoad];
RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//這里進(jìn)行網(wǎng)絡(luò)請(qǐng)求
[subscriber sendNext:@"0000000"];
return nil;
}];
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//這里進(jìn)行網(wǎng)絡(luò)請(qǐng)求
[subscriber sendNext:@"1111111"];
return nil;
}];
/*
selector方法參數(shù)個(gè)數(shù)必須與信號(hào)數(shù)組個(gè)數(shù)一致,表示獲得到的數(shù)據(jù)
rac_liftSelector:必須信號(hào)數(shù)組中的信號(hào)都發(fā)送數(shù)據(jù)才會(huì)進(jìn)入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, ...#>):用于給某個(gè)對(duì)象的某個(gè)屬性綁定
// 監(jiān)聽文本框內(nèi)容
[_textField.rac_textSignal subscribeNext:^(id x) {
_label.text = x;
}];
//使用RAC宏:
// 用來給某個(gè)對(duì)象的某個(gè)屬性綁定信號(hào),只要產(chǎn)生信號(hào)內(nèi)容,就會(huì)把內(nèi)容給屬性賦值
RAC(_label,text) = _textField.rac_textSignal;
2、RACObserve(self, name):監(jiān)聽某個(gè)對(duì)象的某個(gè)屬性,返回的是信號(hào)
[RACObserve(self.view, frame) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
3、@weakify(Obj)和@strongify(Obj),一般兩個(gè)都是配套使用,解決循環(huán)引用問題.
//在block外使用@weakify(self),在block內(nèi)使用@strongify(self),可以防止block內(nèi)使用self出現(xiàn)循環(huán)引用
4、RACTuplePack:把數(shù)據(jù)包裝成RACTuple(元組類)
// 包裝元組
RACTuple *tuple = RACTuplePack(@1,@2);
NSLog(@"%@",tuple[0]);
5、RACTupleUnpack:把RACTuple(元組類)解包成對(duì)應(yīng)的數(shù)據(jù)
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操作思想
運(yùn)用的是==Hook(鉤子)思想==,Hook是一種用于改變API(應(yīng)用程序編程接口:方法)執(zhí)行結(jié)果的技術(shù).
Hook用處:截獲API調(diào)用的技術(shù)。
Hook原理:在每次調(diào)用一個(gè)API返回結(jié)果之前,先執(zhí)行你自己的方法,改變結(jié)果的輸出。
RAC開發(fā)方式:RAC中核心開發(fā)方式,也是綁定,之前的開發(fā)方式是賦值,而用RAC開發(fā),應(yīng)該把重心放在綁定,也就是可以在創(chuàng)建一個(gè)對(duì)象的時(shí)候,就綁定好以后想要做的事情,而不是等賦值之后在去做事情。
列如:把數(shù)據(jù)展示到控件上,之前都是重寫控件的setModel方法,用RAC就可以在一開始創(chuàng)建控件的時(shí)候,就綁定好數(shù)據(jù)。
1、核心方法bind
一般不會(huì)使用bind方法,因?yàn)楸容^底層
給RAC中的信號(hào)進(jìn)行綁定,只要信號(hào)一發(fā)送數(shù)據(jù),就能監(jiān)聽到,從而把發(fā)送數(shù)據(jù)改成自己想要的數(shù)據(jù)
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop){
value = [NSString stringWithFormat:@"changed:%@",value];
/*
在這里修改獲取到的數(shù)據(jù)
*/
return [RACReturnSignal return:value];
};
}];
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"數(shù)據(jù)"];
監(jiān)聽文本框的內(nèi)容,并綁定
[[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)建信號(hào)
RACSubject *subject = [RACSubject subject];
//2、綁定信號(hào)
RACSignal *bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
//這里的block只要原信號(hào)發(fā)送數(shù)據(jù)就會(huì)調(diào)用
value = [NSString stringWithFormat:@"lcy:%@",value];
return [RACReturnSignal return:value];
}];
//3、訂閱信號(hào)
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//4、發(fā)送數(shù)據(jù)
[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
按一定順序拼接信號(hào),當(dāng)多個(gè)信號(hào)發(fā)出的時(shí)候,有順序的接收信號(hào)。
==注意==:組合中第一個(gè)信號(hào)一定要調(diào)用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據(jù)");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據(jù)");
[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ù)據(jù)
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ù)據(jù)
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello B
(2)then
用于連接兩個(gè)信號(hào),當(dāng)?shù)谝粋€(gè)信號(hào)完成,才會(huì)連接then返回的信號(hào),then會(huì)完全忽略第一個(gè)信號(hào)的數(shù)據(jù)
==注意==:組合中第一個(gè)信號(hào)一定要調(diào)用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據(jù)");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據(jù)");
[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ù)據(jù)
2017-07-28 16:38:18.440 RAC_learning[3280:196164] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:38:18.440 RAC_learning[3280:196164] hello B
(3)merge
把多個(gè)信號(hào)合并為一個(gè)信號(hào),任何一個(gè)信號(hào)有新值的時(shí)候就會(huì)調(diào)用
不需要調(diào)用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據(jù)");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據(jù)");
[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ù)據(jù)
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ù)據(jù)
2017-07-28 16:46:06.472 RAC_learning[3563:202620] hello B
(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è)==元組==(RACTuple),才會(huì)觸發(fā)壓縮流的next事件
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送A的數(shù)據(jù)");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送B的數(shù)據(jù)");
[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ù)據(jù)
2017-07-28 16:52:44.201 RAC_learning[3630:205690] 發(fā)送B的數(shù)據(jù)
2017-07-28 16:52:44.204 RAC_learning[3630:205690] <RACTwoTuple: 0x6000000173b0> (
"hello A",
"hello B"
)
(5)combineLatest
將多個(gè)信號(hào)合并起來,并且拿到各個(gè)信號(hào)的最新的值,必須每個(gè)合并的signal至少都有過一次sendNext,才會(huì)觸發(fā)合并的信號(hào)
(6)reduce
用于信號(hào)發(fā)出的內(nèi)容是元組,把信號(hào)發(fā)出元組的值聚合成一個(gè)值
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ù)據(jù):%@",x);
// }];
//使登錄按鈕在用戶名和密碼框都有數(shù)據(jù)的時(shí)候才會(huì)調(diào)用
RAC(self.loginButton, enabled) = signal;
4、ReactiveCocoa操作方法之過濾
(1)filter
過濾信號(hào),使用它可以獲取滿足條件的信號(hào)
RACSignal *signal = [self.nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
//表示當(dāng)文本框輸入的長度超過六位的時(shí)候
return value.length > 6;
}];
[signal subscribeNext:^(id _Nullable x) {
//只有滿足條件的時(shí)候才會(huì)進(jìn)入這個(gè)block
NSLog(@"%@",x);
}];
(2)ignore
忽略完某些值的信號(hào).
[[self.nameTF.rac_textSignal ignore:@"000"] subscribeNext:^(NSString * _Nullable x) {
//忽略了字符串是000的值
NSLog(@"%@",x);
}];
(3)distinctUntilChanged
當(dāng)上一次的值和當(dāng)前的值有明顯的變化就會(huì)發(fā)出信號(hào),否則會(huì)被忽略掉
[[self.nameTF.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
(4)take
從開始一共取N次的信號(hào)
[[self.nameTF.rac_textSignal take:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
// 1、創(chuàng)建信號(hào)
RACSubject *signal = [RACSubject subject];
// 2、處理信號(hào),訂閱信號(hào)
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.發(fā)送信號(hào)
[signal sendNext:@1];
[signal sendNext:@2];
(5)takeLast
取最后N次的信號(hào)
==前提條件==:訂閱者必須調(diào)用完成,因?yàn)橹挥型瓿桑椭揽偣灿卸嗌傩盘?hào)
==注意==:一定要調(diào)用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
獲取信號(hào)直到執(zhí)行完這個(gè)信號(hào)
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)聽文本框的改變,直到當(dāng)前對(duì)象被銷毀
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
(7)skip:(NSUInteger)
跳過幾個(gè)信號(hào),不接受
[[self.nameTF.rac_textSignal skip:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
5、ReactiveCocoa操作方法之秩序
doNext: 執(zhí)行Next之前,會(huì)先執(zhí)行這個(gè)Block
doCompleted: 執(zhí)行sendCompleted之前,會(huì)先執(zhí)行這個(gè)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: 內(nèi)容傳遞切換到制定線程中,副作用在原來線程中,把在創(chuàng)建信號(hào)時(shí)block中的代碼稱之為副作用。
subscribeOn: 內(nèi)容傳遞和副作用都會(huì)切換到制定線程中。
7、ReactiveCocoa操作方法之時(shí)間
(1)timeout
超時(shí),可以讓一個(gè)信號(hào)在一定的時(shí)間后,自動(dòng)報(bào)錯(cuò)
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秒后會(huì)自動(dòng)調(diào)用
NSLog(@"%@",error);
}];
(2)interval
定時(shí),每隔一段時(shí)間發(fā)出信號(hào)
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操作方法之重復(fù)
(1)retry重試
只要失敗,就會(huì)重新執(zhí)行創(chuàng)建信號(hào)中的block,直到成功.
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@1];
}else{
NSLog(@"接收到錯(cuò)誤");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
(2)replay重放
當(dāng)一個(gè)信號(hào)被多次訂閱,反復(fù)播放內(nèi)容
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//只會(huì)進(jìn)入這個(gè)block一次,不會(huì)反復(fù)進(jìn)入
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一個(gè)訂閱者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二個(gè)訂閱者%@",x);
}];
(3)throttle節(jié)流
當(dāng)某個(gè)信號(hào)發(fā)送比較頻繁時(shí),可以使用節(jié)流,在某一段時(shí)間不發(fā)送信號(hào)內(nèi)容,過了一段時(shí)間獲取信號(hào)的最新內(nèi)容發(fā)出。
R
ACSubject *signal = [RACSubject subject];
_signal = signal;
// 節(jié)流,在一定時(shí)間(1秒)內(nèi),不接收任何信號(hào)內(nèi)容,過了這個(gè)時(shí)間(1秒)獲取最后發(fā)送的信號(hào)內(nèi)容發(fā)出。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];