今天來說一說RAC操作符的具體使用,使用操作符會讓你的代碼邏輯更清晰。如果對于之前的有遺忘,可以回顧下之前的文章上手其實很簡單(一)、上手其實很簡單(二)。接下來我們開始我們的學(xué)習(xí)。
RAC映射:
map:把源信號的值映射成一個新的值
**使用步驟: **
1.傳入一個block,類型是返回對象,參數(shù)是value
2.value就是源信號的內(nèi)容,直接拿到源信號的內(nèi)容做處理
3.把處理好的內(nèi)容,直接返回就好了,不用包裝成信號,返回的值,就是映射的值。
例子:
-(void)map {
RACSubject *subject = [RACSubject subject];
// 綁定信號
RACSignal *bindSignal = [subject map:^id(id value) {
// 返回的類型就是你需要映射的值
return [NSString stringWithFormat:@"添加下前綴:%@", value]; //拼接下傳過來的值,映射返回出去
}];
// 訂閱綁定信號
[bindSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[subject sendNext:@"123"];
}
FlatternMap:功能和map相同,主要用于信號中的信號
下邊來坐下比較在處理信號中的信號的幾種方法:
- (void)flattenMap2 {
// flattenMap 主要用于信號中的信號
//signalOfsignals用FlatternMap
// 創(chuàng)建信號
RACSubject *signalofSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
// 訂閱信號
//方式1 一般不使用這個方法套的層數(shù)太多。
// [signalofSignals subscribeNext:^(id x) {
//
// [x subscribeNext:^(id x) {
// NSLog(@"%@", x);
// }];
// }];
// 方式2 這個在上篇文章(二)有介紹
// [signalofSignals.switchToLatest ];
// 方式3 是flattenMap和訂閱分開處理
// RACSignal *bignSignal = [signalofSignals flattenMap:^RACStream *(id value) {
//
// //value:就是源信號發(fā)送內(nèi)容
// return value;
// }];
// [bignSignal subscribeNext:^(id x) {
// NSLog(@"%@", x);
// }];
// 方式4--------也是開發(fā)中常用的 (方法4和方法3相同,只不過4是把訂閱跟flattenMap放到了一起來處理)
[[signalofSignals flattenMap:^RACStream *(id value) {
return value;
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[signalofSignals sendNext:signal];
[signal sendNext:@"123"];
}
map與flattenMap的區(qū)別:
1.FlatternMap中的Block返回信號。
2.Map中的Block返回對象。
3.開發(fā)中,如果信號發(fā)出的值不是信號,映射一般使用Map
4.開發(fā)中,如果信號發(fā)出的值是信號,映射一般使用FlatternMap。
RAC過濾
skip:skip傳入n跳過前面n個值
使用場景: 在實際開發(fā)中比如 后臺返回的數(shù)據(jù)前面幾個沒用,我們想跳躍過去,便可以用skip
- (void)skip {
RACSubject *subject = [RACSubject subject];
[[subject skip:2] subscribeNext:^(id x) {
NSLog(@"%@", x); //會打印第三個值
}];
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
}
distinctUntilChanged:-- 如果當(dāng)前的值跟上一次的值一樣,就不會被訂閱到
使用場景:處理解決相同值沒必要多次被訂閱
- (void)distinctUntilChanged {
RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@2]; // 不會被訂閱
}
** take:**可以屏蔽一些值,去前面幾個值---這里take為2 則只拿到前兩個值
- (void)take {
RACSubject *subject = [RACSubject subject];
[[subject take:2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
}
takeLast:和take的用法一樣,不過他取的是最后的幾個值,如下,則取的是最后兩個值
注意點:takeLast 一定要調(diào)用sendCompleted,告訴他發(fā)送完成了,這樣才能取到最后的幾個值
- (void)takeLast {
RACSubject *subject = [RACSubject subject];
[[subject takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
[subject sendCompleted]; //一定要sendCompleted 否則takeLast取不到最后你想要的值
}
** takeUntil:**---給takeUntil傳的是哪個信號,那么當(dāng)這個信號發(fā)送信號或sendCompleted,就不能再接受源信號的內(nèi)容了。
- (void)takeUntil {
RACSubject *subject = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[[subject takeUntil:subject2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號
[subject sendNext:@1];
[subject sendNext:@2];
[subject2 sendNext:@3]; // 1 調(diào)用后上邊訂閱不會收到下邊發(fā)送的內(nèi)容
// [subject2 sendCompleted]; // 或2 同理一樣不會收到下邊發(fā)送的內(nèi)容
[subject sendNext:@4];
}
ignore: 忽略掉一些值
- (void)ignore {
//ignore:忽略一些值
//ignoreValues:表示忽略所有的值
// 1.創(chuàng)建信號
RACSubject *subject = [RACSubject subject];
// 2.忽略一些值
RACSignal *ignoreSignal = [subject ignore:@2]; // ignoreValues:表示忽略所有的值
// 3.訂閱信號
[ignoreSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 4.發(fā)送數(shù)據(jù)
[subject sendNext:@2];
}
fliter:對于過濾而言,下邊的才是經(jīng)常使用的, 一般和文本框一起用,添加過濾條件
- (void)fliter {
// 只有當(dāng)文本框的內(nèi)容長度大于5,才獲取文本框里的內(nèi)容
[[self.textField.rac_textSignal filter:^BOOL(id value) {
// value 源信號的內(nèi)容
return [value length] > 5;
// 返回值 就是過濾條件。只有滿足這個條件才能獲取到內(nèi)容
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
}
RAC合并操作
combineLatest:把多個信號聚合成你想要的信號
使用場景:比如-當(dāng)多個輸入框都有值的時候按鈕才可點擊,就是把輸入框輸入值的信號都聚合成按鈕是否能點擊的信號。
- (void)combineLatest {
RACSignal *combinSignal = [RACSignal combineLatest:@[self.accountField.rac_textSignal, self.pwdField.rac_textSignal] reduce:^id(NSString *account, NSString *pwd){ //reduce里的參數(shù)一定要和combineLatest數(shù)組里的一一對應(yīng)。
// block: 只要源信號發(fā)送內(nèi)容,就會調(diào)用,組合成一個新值。
NSLog(@"%@ %@", account, pwd);
return @(account.length && pwd.length);
}];
RAC(self.loginBtn, enabled) = combinSignal;
}
zipWith:把兩個信號壓縮成一個信號,只有當(dāng)兩個信號同時發(fā)出信號內(nèi)容時,并且把兩個信號的內(nèi)容合并成一個元祖,才會觸發(fā)壓縮流的next事件。
使用場:當(dāng)一個界面多個請求的時候,要等所有請求完成才更新UI
注意:元組內(nèi)元素的順序跟發(fā)送的順序無關(guān),而是跟壓縮的順序有關(guān)[signalA zipWith:signalB]---先是A后是B
- (void)zipWith {
// 創(chuàng)建信號A
RACSubject *signalA = [RACSubject subject];
// 創(chuàng)建信號B
RACSubject *signalB = [RACSubject subject];
// 壓縮成一個信號
// 等所有信號都發(fā)送內(nèi)容的時候才會調(diào)用
RACSignal *zipSignal = [signalA zipWith:signalB];
[zipSignal subscribeNext:^(id x) {
NSLog(@"%@", x); //所有的值都被包裝成了元組
}];
//發(fā)送信號 交互順序,元組內(nèi)元素的順序不會變,跟發(fā)送的順序無關(guān),而是跟壓縮的順序有關(guān)[signalA zipWith:signalB]---先是A后是B
[signalA sendNext:@1];
[signalB sendNext:@2];
}
** merge:**多個信號合并成一個信號,任何一個信號有新值就會調(diào)用 ,任何一個信號請求完成都會被訂閱到
- (void)merge {
// 創(chuàng)建信號A
RACSubject *signalA = [RACSubject subject];
// 創(chuàng)建信號B
RACSubject *signalB = [RACSubject subject];
//組合信號
RACSignal *mergeSignal = [signalA merge:signalB];
// 訂閱信號
[mergeSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 發(fā)送信號---交換位置則數(shù)據(jù)結(jié)果順序也會交換
[signalB sendNext:@"下部分"];
[signalA sendNext:@"上部分"];
}
** then **使用需求:有兩部分?jǐn)?shù)據(jù):想讓上部分先進(jìn)行網(wǎng)絡(luò)請求但是過濾掉數(shù)據(jù),然后進(jìn)行下部分的,拿到下部分?jǐn)?shù)據(jù)
- (void)then {
// 創(chuàng)建信號A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求
NSLog(@"----發(fā)送上部分請求---afn");
[subscriber sendNext:@"上部分?jǐn)?shù)據(jù)"];
[subscriber sendCompleted]; // 必須要調(diào)用sendCompleted方法!
return nil;
}];
// 創(chuàng)建信號B,
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求
NSLog(@"--發(fā)送下部分請求--afn");
[subscriber sendNext:@"下部分?jǐn)?shù)據(jù)"];
[subscriber sendCompleted];
return nil;
}];
// 創(chuàng)建組合信號
// then;忽略掉第一個信號的所有值
RACSignal *thenSignal = [signalA then:^RACSignal *{
// 返回的信號就是要組合的信號
return signalsB;
}];
// 訂閱信號
[thenSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
}
concat----- 使用需求:有兩部分?jǐn)?shù)據(jù):想讓上部分先執(zhí)行,完了之后再讓下部分執(zhí)行(都可獲取值) ,類似于同步
- (void)concat {
// 組合
// 創(chuàng)建信號A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求
// NSLog(@"----發(fā)送上部分請求---afn");
[subscriber sendNext:@"上部分?jǐn)?shù)據(jù)"];
[subscriber sendCompleted]; // 必須要調(diào)用sendCompleted方法!
return nil;
}];
// 創(chuàng)建信號B,
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 發(fā)送請求
// NSLog(@"--發(fā)送下部分請求--afn");
[subscriber sendNext:@"下部分?jǐn)?shù)據(jù)"];
return nil;
}];
// concat:按順序去鏈接
//**-注意-**:concat,第一個信號必須要調(diào)用sendCompleted
// 創(chuàng)建組合信號
RACSignal *concatSignal = [signalA concat:signalsB];
// 訂閱組合信號
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
RAC常用的宏
RAC宏 :
- (void)test
{
// RAC:把一個對象的某個屬性綁定一個信號,只要發(fā)出信號,就會把信號的內(nèi)容給對象的屬性賦值
// 給label的text屬性綁定了文本框改變的信號
RAC(self.label, text) = self.textField.rac_textSignal;
}
KVO RACObserveL:快速的監(jiān)聽某個對象的某個屬性改變 返回的是一個信號,對象的某個屬性改變的信號
- (void)test2 {
[RACObserve(self.view, center) subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
}
- (void)testAndtest2 // textField輸入的值賦值給label,監(jiān)聽label文字改變,
{
RAC(self.label, text) = self.textField.rac_textSignal;
[RACObserve(self.label, text) subscribeNext:^(id x) {
NSLog(@"====label的文字變了");
}];
RAC(self.label, text) = RACObserve( self.textField, text) ;
}
** 循環(huán)引用問題 **
- (void)test3 {
@weakify(self)
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
@strongify(self)
NSLog(@"%@",self.view);
return nil;
}];
_signal = signal;
}
** 元組:**
//快速包裝一個元組 ,把包裝的類型放在宏的參數(shù)里面,就會自動包裝
- (void)test4 {
RACTuple *tuple = RACTuplePack(@1,@2,@4);
// 宏的參數(shù)類型要和元祖中元素類型一致, 右邊為要解析的元祖。
RACTupleUnpack_(NSNumber *num1, NSNumber *num2, NSNumber * num3) = tuple;// 4.元祖
// 快速包裝一個元組
// 把包裝的類型放在宏的參數(shù)里面,就會自動包裝
NSLog(@"%@ %@ %@", num1, num2, num3);
}