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

相关文章
相关标签/搜索