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