ReactiveCocoa入门第二篇过滤器学习笔记
信号的过滤
一个Signal源可以产生一系列next值,但并非所有值都是需要的,具体的Subscriber可以选择在原有Signal上套用Filter操作来过滤掉不需要的值。
经过总结,这些filter大概可以分成两类:next值过滤类型和起止点过滤类型
值过滤类型Filters
– filter: (BOOL (^)(id value))
[[self.inputTextField.rac_textSignal filter:^BOOL(NSString *value) {
return [value hasPrefix:@"sunny"];
}] subscribeNext:^(NSString *value) {
NSLog(@"This value has prefix `sunny` : %@", value);
}];
– ignore: (id)
忽略给定的值,注意,这里忽略的既可以是地址相同的对象,也可以是- isEqual:结果相同的值,也就是说自己写的Model对象可以通过重写- isEqual:方法来使- ignore:生效。
[[self.inputTextField.rac_textSignal ignore:@"sunny"] subscribeNext:^(NSString *value) {
NSLog(@"`sunny` could never appear : %@", value);
}];
– ignoreValues
这个比较极端,忽略所有值,只关心Signal结束,也就是只取Comletion和Error两个消息,中间所有值都丢弃。
注意,这个操作应该出现在Signal有终止条件的的情况下,如rac_textSignal这样除dealloc外没有终止条件的Signal上就不太可能用到。
– distinctUntilChanged
也是一个相当常用的Filter(但它不是- filter:的衍生方法),它将这一次的值与上一次做比较,当相同时(也包括- isEqual:)被忽略掉。
比如UI上一个Label绑定了一个值,根据值更新显示的内容:
RAC(self.label, text) = [RACObserve(self.user, username) distinctUntilChanged];
self.user.username = @"sunnyxx"; // 1st
self.user.username = @"sunnyxx"; // 2nd
self.user.username = @"sunnyxx"; // 3rd
起止点过滤类型
除了被动的当next值来的时候做判断,也可以主动的提前选择开始和结束条件,分为两种类型:
take型(取)和skip型(跳)
– take: (NSUInteger)
从开始一共取N次的next值,不包括Competion和Error,如:
[[[RACSignal createSignal:^RACDisposable *(id 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完成前一直取值。最简单的栗子就是UITextField的rac_textSignal的实现(删减版本):
- (RACSignal *)rac_textSignal {
@weakify(self);
return [[[[[RACSignal
concat:[self rac_signalForControlEvents:UIControlEventEditingChanged]]
map:^(UITextField *x) {
return x.text;
}]
takeUntil:self.rac_willDeallocSignal] // bingo!
}