原文:点这里
这个文档说明了一些经常使用的操作,并且有例子说明. 操作主要是运用序列(sequences)和信号(signal)的流(stream)操作.
Side Effect: 信号的副作用, 边际效应 (本人的理解..)
用信号实现信号的副作用
绝大多数信号创建的时候是 “冷信号”, 即直到信号被订阅后才能执行的信号. 在订阅的基础上, 信号或者订阅者可以执行一些信号的副作用方法, 比如输出一些log, 发起网络请求, 更新UI等等. 副作用方法也可以注入到信号中, 当然不会立即执行, 但是执行后会影响所有的订阅者.
订阅(Subscription)
在方法中带有前缀 -subscribe…
的方法,可以从一个信号中获得当前和以后的值.
RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal;
// Outputs: A B C D E F G H I
[letters subscribeNext:^(NSString *x) {
NSLog(@"%@", x);
}];
对于冷信号, 副作用方法会在每次的订阅中执行
__block unsigned subscriptions = 0;
RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
subscriptions++;
[subscriber sendCompleted];
return nil;
}];
// Outputs:
// subscription 1
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];
// Outputs:
// subscription 2
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];
这些操作也可以使用 connenction来实现.
注入的影响 (信号内部的)
带有 -do...
前缀的方法会产生副作用, 但是不会真的订阅信号
__block unsigned subscriptions = 0;
RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
subscriptions++;
[subscriber sendCompleted];
return nil;
}];
// Does not output anything yet
loggingSignal = [loggingSignal doCompleted:^{
NSLog(@"about to complete subscription %u", subscriptions);
}];
// Outputs:
// about to complete subscription 1
// subscription 1
[loggingSignal subscribeCompleted:^{
NSLog(@"subscription %u", subscriptions);
}];
信号流转换
这些方法将一个信号转换成一个新的信号
Mapping 转换
-map
方法用于将数值转换成信号, 创建一个包含结果值的信号
RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence;
// Contains: AA BB CC DD EE FF GG HH II
RACSequence *mapped = [letters map:^(NSString *value) {
return [value stringByAppendingString:value];
}];
[mapped.signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
Filtering 过滤
-filter
方法使用了一个block来过滤每一个输入的值, 符合条件的值才能输出
RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;
// Contains: 2 4 6 8
RACSequence *filtered = [numbers filter:^ BOOL (NSString *value) {
return (value.intValue % 2) == 0;
}];
Combining streams 信号合并
这个方法会将很多信号源合并成一个信号源
Concatenating 连接
-concat:
方法将一个信号连接到另一个信号后面
RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence;
RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;
// Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9
RACSequence *concatenated = [letters concat:numbers];
Flattening 平铺
-flatten:
方法应用于从信号流到信号流的, 然后合并成一个新的流.
下面的序列是串行的:
RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence;
RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;
RACSequence *sequenceOfSequences = @[ letters, numbers ].rac_sequence;
// Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9
RACSequence *flattened = [sequenceOfSequences flatten];
下面的序列是合并的:
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSignal *signalOfSignals = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
[subscriber sendNext:letters];
[subscriber sendNext:numbers];
[subscriber sendCompleted];
return nil;
}];
RACSignal *flattened = [signalOfSignals flatten];
// Outputs: A 1 B C 2
[flattened subscribeNext:^(NSString *x) {
NSLog(@"%@", x);
}];
[letters sendNext:@"A"];
[numbers sendNext:@"1"];
[letters sendNext:@"B"];
[letters sendNext:@"C"];
[numbers sendNext:@"2"];
Mapping and flattening 转换平铺
-flattenMap:
方法用于转换每一个流的值到一个新的流中, 然后将所有新的流合并成一个流传递下去. 也就是 先执行 -map
然后执行 -flatten
下面是用于扩展和编辑序列的例子:
RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;
// Contains: 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
RACSequence *extended = [numbers flattenMap:^(NSString *num) {
return @[ num, num ].rac_sequence;
}];
// Contains: 1_ 3_ 5_ 7_ 9_
RACSequence *edited = [numbers flattenMap:^(NSString *num) {
if (num.intValue % 2 == 0) {
return [RACSequence empty];
} else {
NSString *newNum = [num stringByAppendingString:@"_"];
return [RACSequence return:newNum];
}
}];
或者创建多个工作信号
RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal;
[[letters
flattenMap:^(NSString *letter) {
return [database saveEntriesForLetter:letter];
}]
subscribeCompleted:^{
NSLog(@"All database entries saved successfully.");
}];
Combining signals 合并信号
这些方法将多个信号合并成一个 RACSignal 对象
Sequencing 排序
-then
方法会等待信号结束,然后将数值转换成一个信号
RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal;
// The new signal only contains: 1 2 3 4 5 6 7 8 9
//
// But when subscribed to, it also outputs: A B C D E F G H I
RACSignal *sequenced = [[letters
doNext:^(NSString *letter) {
NSLog(@"%@", letter);
}]
then:^{
return [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence.signal;
}];
这个方法对于执行一个信号的所有副作用方法后, 再只执行另一个方法, 然后返回第二个信号的值 是很有用的.
Merging 合并
+merge:
方法会将许多信号的的值转换成一个信号, 只要有值输入,就会转换
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSignal *merged = [RACSignal merge:@[ letters, numbers ]];
// Outputs: A 1 B C 2
[merged subscribeNext:^(NSString *x) {
NSLog(@"%@", x);
}];
[letters sendNext:@"A"];
[numbers sendNext:@"1"];
[letters sendNext:@"B"];
[letters sendNext:@"C"];
[numbers sendNext:@"2"];
Combining latest values 绑定最新的值
+combineLatest:
方法会监听多个信号的值的变化,有一个值变化, 就将最新的值输出
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSignal *combined = [RACSignal
combineLatest:@[ letters, numbers ]
reduce:^(NSString *letter, NSString *number) {
return [letter stringByAppendingString:number];
}];
// Outputs: B1 B2 C2 C3
[combined subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
[letters sendNext:@"A"];
[letters sendNext:@"B"];
[numbers sendNext:@"1"];
[numbers sendNext:@"2"];
[letters sendNext:@"C"];
[numbers sendNext:@"3"];
注意: 合并信号后, 只有当所有的信号都至少发送了一个值的时候, 合并的信号才发出第一次信号值. 上面的例子中 “A” 不会输出, 因为 numbers 还没有第一次输出值
Switching 切换
-switchToLatest:
方法会切换输入信号源来输出结果, 每次sendNext一个新的信号, 输出会按照新的信号输出,可以随时切换输入源的信号
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSubject *signalOfSignals = [RACSubject subject];
RACSignal *switched = [signalOfSignals switchToLatest];
// Outputs: A B 1 D
[switched subscribeNext:^(NSString *x) {
NSLog(@"%@", x);
}];
[signalOfSignals sendNext:letters];
[letters sendNext:@"A"];
[letters sendNext:@"B"];
[signalOfSignals sendNext:numbers];
[letters sendNext:@"C"];
[numbers sendNext:@"1"];
[signalOfSignals sendNext:letters];
[numbers sendNext:@"2"];
[letters sendNext:@"D"];