Reactive Cocoa Tutorial [4] = 只取所需的Filters

本文原文發表自個人【自建博客】,cnblogs同步發表,格式未經調整,內容以原博客爲準

注:因爲拖延症和最近因項目暫緩了RAC的研究,Reactive Cocoa Tutorial系列文章更新很慢,最近醒悟,開始慢慢補上剩下的部分,請見諒。git

 

 

我是前言

這是Reactive Cocoa Tutorial系列其中的一篇,上一篇簡單介紹了RAC中最重要的RACSignal,下面幾篇文章將主要從它的Operations下手,這也是工程中使用RAC的重點。從簡到難,本篇文章先介紹RAC消息流的過濾器-Filters類別的相關方法。github


RAC中的Filters

畫個範圍

一個Signal源能夠產生一系列next值,但並不是全部值都是須要的,具體的Subscriber能夠選擇在原有Signal上套用Filter操做來過濾掉不須要的值。
個人定義:RAC中若是一個Operation將處理後的值集合是處理前值集合的子集,咱們就能夠把它歸爲Filter類型。數據庫

固然經過以前介紹的基礎操做徹底能夠本身拼出個想要的filter來,RAC爲了方便使用已經實現了幾個經常使用的filter,通過總結,這些filter大概能夠分紅兩類:next值過濾類型起止點過濾類型網絡

值過濾類型Filters

- filter: (BOOL (^)(id value))

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

- ignore: (id)

忽略給定的值,注意,這裏忽略的既能夠是地址相同的對象,也能夠是- isEqual:結果相同的值,也就是說本身寫的Model對象能夠經過重寫- isEqual:方法來使- ignore:生效。經常使用的值的判斷沒有問題,以下:spa

1
2
3
[[self.inputTextField.rac_textSignal ignore:@"sunny"] subscribeNext:^(NSString *value) {
    NSLog(@"`sunny` could never appear : %@", value);
}];

- ignoreValues

這個比較極端,忽略全部值,只關心Signal結束,也就是隻取ComletionError兩個消息,中間全部值都丟棄。
注意,這個操做應該出如今Signal有終止條件的的狀況下,如rac_textSignal這樣除dealloc外沒有終止條件的Signal上就不太可能用到。code

- distinctUntilChanged

也是一個至關經常使用的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型(跳)

- take: (NSUInteger)

從開始一共取N次的next值,不包括CompetionError,如:

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);
}];

- takeLast: (NSUInteger)

取最後N次的next值,注意,因爲一開始不能知道這個Signal將有多少個next值,因此RAC實現它的方法是將全部next值都存起來,而後原Signal完成時再將後N個依次發送給接收者,但Error發生時依然是馬上發送的。

- takeUntil:(RACSignal *)

當給定的signal完成前一直取值。最簡單的栗子就是UITextFieldrac_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時才中止

- takeUntilBlock:(BOOL (^)(id x))

對於每一個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);
}];

- takeWhileBlock:(BOOL (^)(id x))

上面的反向邏輯,對於每一個next值,block返回 YES時才取值

- skip:(NSUInteger)

從開始跳過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);
}];

- skipUntilBlock:(BOOL (^)(id x))

- takeUntilBlock:同理,一直跳,直到block爲YES

- skipWhileBlock:(BOOL (^)(id x))

- takeWhileBlock:同理,一直跳,直到block爲NO


總結

本章介紹了RAC中Filter類型的Operation,總結一下:

  • 適用場景:須要一個next值集合的子集
  • Filter類型:值過濾型和起止點過濾型
  • 值過濾型經常使用方法: -filter:-ignore:-distinctUnitlChanged
  • 起止點過濾型經常使用方法:take系列和skip系列

References

https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/BasicOperators.md#filtering


原創文章,轉載請註明源地址,blog.sunnyxx.com

相關文章
相關標籤/搜索