6 RAC終結(jié)篇
6.1 映射
RAC的映射主要有兩個(gè)方法(flattenMap map),這兩個(gè)方法主要用于將信號(hào)源的內(nèi)容映射成為一個(gè)新的信號(hào)。
-
flattenMap
它其實(shí)也是綁定信號(hào),一般用于信號(hào)中的信號(hào)。
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
value = [NSString stringWithFormat:@"處理數(shù)據(jù):%@",value];
//返回信號(hào)用來(lái)包裝修改過(guò)的內(nèi)容
return [RACReturnSignal return:value];
}];
//訂閱綁定信號(hào)
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//發(fā)送數(shù)據(jù)
[subject sendNext:@"123"];
運(yùn)行如圖:

看起來(lái)有點(diǎn)繞,說(shuō)白了我們?cè)谑裁磮?chǎng)景下會(huì)用到這種呢?
就在我們發(fā)送的數(shù)據(jù),需要對(duì)數(shù)據(jù)進(jìn)行處理然后再訂閱這個(gè)信號(hào)的時(shí)候就可以使用這種方式,其實(shí)跟我們上一節(jié)中提到的
bind是一樣的。
- map
這個(gè)方法跟flattenMap稍微有一點(diǎn)不同,他的block返回值是一個(gè)id類型,而flattenMap是一個(gè)信號(hào)。
也就是說(shuō)不用在返回信號(hào)了,直接返回一個(gè)數(shù)據(jù),返回的數(shù)據(jù)就是處理后的數(shù)據(jù)。
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [subject map:^id _Nullable(id _Nullable value) {
//返回的數(shù)據(jù)就是需要處理的數(shù)據(jù)
return [NSString stringWithFormat:@"%@123",value];
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//發(fā)送數(shù)據(jù)
[subject sendNext:@"我想靜靜"];
運(yùn)行如圖:

6.2 組合
concat:按順序組合。
剛剛我們說(shuō)到了rac_liftSelector的使用場(chǎng)景,它是在等多個(gè)信號(hào)全部都返回?cái)?shù)據(jù)后再刷新UI。那么我們現(xiàn)在有一個(gè)需求,就是按順序刷新UI,也就是說(shuō)你這些接口什么時(shí)候請(qǐng)求完數(shù)據(jù)我并不知道,但是你請(qǐng)求完成后的處理要按照我的順序來(lái)。處理完第一個(gè),再處理第二個(gè)。
//組合!!
//創(chuàng)建信號(hào)!!
RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送請(qǐng)求A");
//發(fā)送數(shù)據(jù)
[subscriber sendNext:@"數(shù)據(jù)A"];
//哥么結(jié)束了!!
[subscriber sendCompleted];
//[subscriber sendError:nil];
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送請(qǐng)求B");
//發(fā)送數(shù)據(jù)
[subscriber sendNext:@"數(shù)據(jù)B"];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送請(qǐng)求C");
//發(fā)送數(shù)據(jù)
[subscriber sendNext:@"數(shù)據(jù)C"];
[subscriber sendCompleted];
return nil;
}];
//concat:按順序組合!!
//創(chuàng)建組合信號(hào)!!
RACSignal * concatSignal = [RACSignal concat:@[signalA,signalB,signalC]];
//訂閱組合信號(hào)
[concatSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
運(yùn)行如圖:

then:
忽略掉前面一個(gè)信號(hào)所有的值,返回后一個(gè)信號(hào)的數(shù)據(jù)。也就是說(shuō)后一個(gè)信號(hào)的數(shù)據(jù)要依賴前一個(gè)信號(hào)的發(fā)送完畢,但我并不需要處理前一個(gè)信號(hào)的數(shù)據(jù)。
//創(chuàng)建信號(hào)!!
RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送請(qǐng)求A");
//發(fā)送數(shù)據(jù)
[subscriber sendNext:@"數(shù)據(jù)A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"發(fā)送請(qǐng)求B");
//發(fā)送數(shù)據(jù)
[subscriber sendNext:@"數(shù)據(jù)B"];
[subscriber sendCompleted];
return nil;
}];
//then:忽略掉第一個(gè)信號(hào)所有的值!!
RACSignal * thenSignal = [signalA then:^RACSignal * _Nonnull{
return signalB;
}];
//訂閱信號(hào)
[thenSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
運(yùn)行如圖:

merge: 無(wú)序組合,誰(shuí)先發(fā)送誰(shuí)先處理。
前面我說(shuō)到的都是有序的,那么肯定也有無(wú)序的組合,假設(shè)我們一般頁(yè)面有N多個(gè)接口的請(qǐng)求,需要來(lái)一個(gè)就顯示一個(gè)。處理的代碼呢也能寫到一起。
//創(chuàng)建信號(hào)
RACSubject * signalA = [RACSubject subject];
RACSubject * signalB = [RACSubject subject];
RACSubject * signalC = [RACSubject subject];
//組合信號(hào)
RACSignal * mergeSignal = [RACSignal merge:@[signalA,signalB,signalC]];
//訂閱 -- 根據(jù)發(fā)送的情況接受數(shù)據(jù)!!
[mergeSignal subscribeNext:^(id _Nullable x) {
//任意一二信號(hào)發(fā)送內(nèi)容就會(huì)來(lái)這個(gè)Block
NSLog(@"%@",x);
}];
//發(fā)送數(shù)據(jù)
[signalC sendNext:@"數(shù)據(jù)C"];
[signalA sendNext:@"數(shù)據(jù)A"];
[signalB sendNext:@"數(shù)據(jù)B"];
運(yùn)行如圖:

zipWith:
兩個(gè)信號(hào)壓縮!只有當(dāng)兩個(gè)信號(hào)同時(shí)發(fā)出信號(hào)內(nèi)容,并且將內(nèi)容合并成為一個(gè)元祖給你
//創(chuàng)建信號(hào)
RACSubject * signalA = [RACSubject subject];
RACSubject * signalB = [RACSubject subject];
//壓縮
RACSignal * zipSignal = [signalA zipWith:signalB];
//接受數(shù)據(jù) 和發(fā)送順序無(wú)關(guān)!!
[zipSignal subscribeNext:^(id _Nullable x) {
RACTupleUnpack(NSString *str1,NSString *str2) = x;
NSLog(@"str1=%@,str2=%@",str1,str2);
}];
//發(fā)送數(shù)據(jù)
//這是一組
[signalB sendNext:@"小明"];
[signalA sendNext:@"小小"];
//這也是一組
[signalB sendNext:@"小明1"];
[signalA sendNext:@"小小1"];
//這也是一組
[signalB sendNext:@"小明2"];
[signalA sendNext:@"小小2"];
運(yùn)行如圖:

這里 只有
signalA、signalB同時(shí)發(fā)送了一次信號(hào),才會(huì)接收到信號(hào),接收到的數(shù)據(jù)是一個(gè)元祖,值就是signalA、signalB發(fā)送的數(shù)據(jù)。
元祖的數(shù)據(jù)順序和你發(fā)送的順序無(wú)關(guān),而是和[signalA zipWith:signalB]這個(gè)方法有關(guān)。
combineLatest: reduce:
組合信號(hào),將多個(gè)信號(hào)的數(shù)據(jù)進(jìn)行合并處理,在返回一個(gè)數(shù)據(jù)給新的信號(hào)。
這個(gè)東西呢,我們我們通過(guò)一個(gè)例子來(lái)說(shuō)明,就拿一個(gè)簡(jiǎn)單的登錄來(lái)說(shuō)把。
首先呢有兩個(gè)輸入框(UITextField),賬號(hào)和密碼,還有一個(gè)按鈕(UIButton),首先這個(gè)按鈕是不可點(diǎn)擊的,當(dāng)兩個(gè)輸入框都有值的情況下呢按鈕才可以點(diǎn)擊。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.placeholder = @"請(qǐng)出入昵稱";
nameTF.backgroundColor = [UIColor yellowColor];
UITextField *pwdTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 120, 200, 50)];
[self.view addSubview:pwdTF];
pwdTF.placeholder = @"請(qǐng)出入密碼";
pwdTF.backgroundColor = [UIColor grayColor];
UIButton *loginBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 180, 100, 50)];
[self.view addSubview:loginBtn];
[loginBtn setTitle:@"登錄" forState:UIControlStateNormal];
[loginBtn setBackgroundColor:[UIColor purpleColor]];
RACSignal *signalBtn = [loginBtn rac_signalForControlEvents:(UIControlEventTouchUpInside)];
[signalBtn subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//組合
//reduceBlock參數(shù):根據(jù)組合的信號(hào)關(guān)聯(lián)的 必須一一對(duì)應(yīng)!!
RACSignal * signal = [RACSignal combineLatest:@[nameTF.rac_textSignal,pwdTF.rac_textSignal] reduce:^id _Nullable(NSString *nickName,NSString * pwd){
//兩個(gè)文本框的text是否有值!!
return @(nickName.length && pwd.length);
}];
RAC(loginBtn,enabled) = signal;
運(yùn)行如圖:

6.3 過(guò)濾
- filter: 當(dāng)滿足特定的條件,才能獲取到訂閱的信號(hào)數(shù)據(jù)。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.backgroundColor = [UIColor yellowColor];
RACSignal *signal = [nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
if (value.length > 5) {
return YES;
}
return nil;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
運(yùn)行如圖:

- ignore:忽略掉哪些值。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.backgroundColor = [UIColor yellowColor];
RACSignal *signal = [nameTF.rac_textSignal ignore:@"a"];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
運(yùn)行如圖:
輸入第一個(gè)a并沒(méi)有監(jiān)聽(tīng)到

- take: 指定拿前面的哪幾條數(shù)據(jù)!!(從前往后)
RACSubject * subject = [RACSubject subject];
//take:指定拿前面的哪幾條數(shù)據(jù)!!(從前往后)
//takeLast:指定拿后面的哪幾條數(shù)據(jù)!!(從后往前)注意點(diǎn):一定要寫結(jié)束!!
[[subject take:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
運(yùn)行如圖:

- takeLast: 指定拿后面的哪幾條數(shù)據(jù)!!(從后往前)注意點(diǎn):一定要寫結(jié)束!!
RACSubject * subject = [RACSubject subject];
//take:指定拿前面的哪幾條數(shù)據(jù)!!(從前往后)
//takeLast:指定拿后面的哪幾條數(shù)據(jù)!!(從后往前)注意點(diǎn):一定要寫結(jié)束!!
[[subject takeLast:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
運(yùn)行如圖:

- takeUntil:直到你的標(biāo)記信號(hào)發(fā)送數(shù)據(jù)的時(shí)候結(jié)束!!!
RACSubject * subject = [RACSubject subject];
//專門做一個(gè)標(biāo)記信號(hào)!!
RACSubject * signal = [RACSubject subject];
//takeUntil:直到你的標(biāo)記信號(hào)發(fā)送數(shù)據(jù)的時(shí)候結(jié)束!!!
[[subject takeUntil:signal] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"靜靜"];
[signal sendNext:@"小明"];//這個(gè)信號(hào)發(fā)送之后就結(jié)束了。
// [signal sendCompleted];//標(biāo)記信號(hào)!! 這個(gè)信號(hào)發(fā)送之后也一樣結(jié)束。
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
當(dāng)signal發(fā)送信號(hào)后,subject的發(fā)送就會(huì)結(jié)束,這里的 3 1 就不會(huì)在發(fā)送了。這種方式也比較常用。
運(yùn)行如圖:

- distinct:忽略掉重復(fù)數(shù)據(jù)
//1.創(chuàng)建信號(hào)
RACSubject * subject = [RACSubject subject];
//忽略掉重復(fù)數(shù)據(jù)
[[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//發(fā)送
[subject sendNext:@"小明"];
[subject sendNext:@"小明"];
[subject sendNext:@"小小"];
[subject sendNext:@"小愛(ài)"];
運(yùn)行如圖:

這樣可以吧。。我們換個(gè)順序好了
看圖:

依舊是兩個(gè)小明,不太靠譜吧
- skip: 跳躍幾個(gè)值
RACSubject * subject = [RACSubject subject];
//skip: 跳躍幾個(gè)值
[[subject skip:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"小明"];
[subject sendNext:@"小小"];
[subject sendNext:@"小紅帽"];
[subject sendNext:@"小愛(ài)"];
[subject sendNext:@"小不點(diǎn)"];
[subject sendNext:@"大灰狼"];
運(yùn)行如圖:
