注:因爲拖延症和最近因項目暫緩了RAC的研究,Reactive Cocoa Tutorial系列文章更新很慢,最近醒悟,開始慢慢補上剩下的部分,請見諒。git
這是Reactive Cocoa Tutorial系列其中的一篇,上一篇簡單介紹了RAC中最重要的RACSignal
,下面幾篇文章將主要從它的Operations
下手,這也是工程中使用RAC的重點。從簡到難,本篇文章先介紹RAC消息流的過濾器-Filters
類別的相關方法。github
一個Signal源能夠產生一系列next值,但並不是全部值都是須要的,具體的Subscriber能夠選擇在原有Signal上套用Filter操做來過濾掉不須要的值。
個人定義:RAC中若是一個Operation
將處理後的值集合是處理前值集合的子集
,咱們就能夠把它歸爲Filter
類型。數據庫
固然經過以前介紹的基礎操做徹底能夠本身拼出個想要的filter來,RAC爲了方便使用已經實現了幾個經常使用的filter,通過總結,這些filter大概能夠分紅兩類:next值過濾類型
和起止點過濾類型
網絡
RAC中的filter同名方法- filter:(BOOL (^)(id value))
,簡單明瞭,將一個value用block作test,返回YES的纔會經過,它的內部實現使用了- flattenMap:
,將原來的Signal
通過過濾轉化成只返回過濾值的Signal
,用法也不難理解:app
1 2 3 4 5 |
[[self.inputTextField.rac_textSignal filter:^BOOL(NSString *value) { return [value hasPrefix:@"sunny"]; }] subscribeNext:^(NSString *value) { NSLog(@"This value has prefix `sunny` : %@", value); }]; |
此外,還有幾個這個方法的衍生方法:ui
忽略給定的值,注意,這裏忽略的既能夠是地址相同的對象,也能夠是- isEqual:
結果相同的值,也就是說本身寫的Model對象能夠經過重寫- isEqual:
方法來使- ignore:
生效。經常使用的值的判斷沒有問題,以下:spa
1 2 3 |
[[self.inputTextField.rac_textSignal ignore:@"sunny"] subscribeNext:^(NSString *value) { NSLog(@"`sunny` could never appear : %@", value); }]; |
這個比較極端,忽略全部值,只關心Signal結束,也就是隻取Comletion
和Error
兩個消息,中間全部值都丟棄。
注意,這個操做應該出如今Signal有終止條件的的狀況下,如rac_textSignal
這樣除dealloc
外沒有終止條件的Signal上就不太可能用到。code
也是一個至關經常使用的Filter(但它不是- filter:的衍生方法),它將這一次的值與上一次作比較,當相同時(也包括- isEqual:
)被忽略掉。
好比UI上一個Label綁定了一個值,根據值更新顯示的內容:regexp
1 2 3 4 |
RAC(self.label, text) = [RACObserve(self.user, username) distinctUntilChanged]; self.user.username = @"sunnyxx"; // 1st self.user.username = @"sunnyxx"; // 2nd self.user.username = @"sunnyxx"; // 3rd |
若是不增長distinctUntilChanged
的話對於連續的相同的輸入值就會有沒必要要的處理,這個栗子只是簡單的UI刷新,但遇到如寫數據庫,髮網絡請求的狀況時,代價就不能購忽略了。對象
因此,對於相同值能夠忽略的狀況,果斷加上它吧。
除了被動的當next值來的時候作判斷,也能夠主動的提早選擇開始和結束條件,分爲兩種類型: take型(取)
和skip型(跳)
從開始一共取N次的next值,不包括Competion
和Error
,如:
1 2 3 4 5 6 7 8 9 |
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"1"]; [subscriber sendNext:@"2"]; [subscriber sendNext:@"3"]; [subscriber sendCompleted]; return nil; }] take:2] subscribeNext:^(id x) { NSLog(@"only 1 and 2 will be print: %@", x); }]; |
取最後N次的next值,注意,因爲一開始不能知道這個Signal將有多少個next值,因此RAC實現它的方法是將全部next值都存起來,而後原Signal完成時再將後N個依次發送給接收者,但Error發生時依然是馬上發送的。
當給定的signal完成前一直取值。最簡單的栗子就是UITextField
的rac_textSignal
的實現(刪減版本):
1 2 3 4 5 6 7 8 9 |
- (RACSignal *)rac_textSignal { @weakify(self); return [[[[[RACSignal concat:[self rac_signalForControlEvents:UIControlEventEditingChanged]] map:^(UITextField *x) { return x.text; }] takeUntil:self.rac_willDeallocSignal] // bingo! } |
也就是這個Signal一直到textField執行dealloc
時才中止
對於每一個next值,運行block,當block返回YES時中止取值,如:
1 2 3 4 5 |
[[self.inputTextField.rac_textSignal takeUntilBlock:^BOOL(NSString *value) { return [value isEqualToString:@"stop"]; }] subscribeNext:^(NSString *value) { NSLog(@"current value is not `stop`: %@", value); }]; |
上面的反向邏輯,對於每一個next值,block返回 YES時才取值
從開始跳過N次的next值,簡單的栗子:
1 2 3 4 5 6 7 8 9 |
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"1"]; [subscriber sendNext:@"2"]; [subscriber sendNext:@"3"]; [subscriber sendCompleted]; return nil; }] skip:1] subscribeNext:^(id x) { NSLog(@"only 2 and 3 will be print: %@", x); }]; |
和- takeUntilBlock:
同理,一直跳,直到block爲YES
和- takeWhileBlock:
同理,一直跳,直到block爲NO
本章介紹了RAC中Filter類型的Operation,總結一下:
子集
時-filter:
,-ignore:
,-distinctUnitlChanged
take
系列和skip
系列https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/BasicOperators.md#filtering
原創文章,轉載請註明源地址,blog.sunnyxx.com