SwitchToLatest:
1、当新的值信号产生的时候,立即订阅最新的值信号。同时把前一个值信号关闭掉,取消订阅。
2、降维后新信号的结束时间:取决于信号最后一个值信号的结束时间。
3、降维后新信号的异常处理:只要有一个值信号产生异常,就会传递下来。
4、图示:
5、应用示例:后续添加,暂时在项目中未摘出 。
//敬请期待
if/then/else
1、作用描述:
每次为Yes是则从信号A的第一个值开始读取信号,知道下一个值为NO时,则从信号B的第一个值开始读取信号。依次反复。每次读取从是从相应信号的第一个值开始。
2、图示:
3、if/then/else的本质:
实质就是先把boolSignal做一个map操作,当为yes时,返回trueSignal,当为No时,返回falseSignal,所以最终我们得到一个高阶信号。详情见下图:
4、使用示例:
Flatten
1、扁平,通常用于高阶信号的降阶操作
2、图示:
Flatten:(NSUInteger)
1、作用:同Flatten作用一致,只不过这里设定了对应参数值。
2、参数值:作用是设定当前栈中的信号数量。flatten对信号做降阶操作时,内部会维护两个栈:当前栈,等待栈。
(2.1)当前栈中用来存放正在订阅的信号,当前栈中的信号只能等信号完成后信号才会从栈中退出。
(2.2)等待栈中用来存放已经产生,但是还没有进行订阅处理的信号。
3、图示:
4、Flatten相关的信号处理函数需要结合实际例子仔细体会。
Concat:
1、上一篇已经讲过concat,这次要从concat的实现上来说一下。
2、concat函数的实现:是通过flatten来封装的。即:concat <=> flatten:1
3、concat两个函数:
- 3.1)concat 高阶多维信号通常使用这个函数
- 3.2) concat:这个函数的实现看源码会发现略有不同。并不是通过flatten来实现。
4、使用示例:实现一个延迟一秒的信号
RACSignal *signal = @[@1, @3, @7,@9, @8].rac_sequence.signal; RACSignal *timerSignal = [[signal map:^id(id value) { return [[RACSignal return:value] delay:1]; }] concat];
FlattenMap
1、FlattenMap的实现是基于bind操作,它的实现是:
传入一个block,然后将这个block作用于原始信号传出的值上,并生成一个新的信号。(新生成的信号是bind函数根据原始信号的值创建的)
2、FlattenMap的实现:
- (instancetype)flattenMap:(RACStream * (^)(id value))block {
Class class = self.class;
return [[self bind:^{
return ^(id value, BOOL *stop) {
id stream = block(value) ?: [class empty];
NSCAssert([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@", stream);
return stream;
};
}] setNameWithFormat:@"[%@] -flattenMap:", self.name];
}
3、FlattenMap的重要性:
(1)很多信号的实现是基于flattenMap,例如:flatten、map、filter
//flatten
RACSignal *flatten = [signalA flattenMap:^RACStream *(RACSignal *value) {
return value;
}];
//map
RACSignal *map = [signalA flattenMap:^RACStream *(id value) {
id anthorValue = value;
return [RACSignal return:anthorValue];
}];
//filter
RACSignal *filter = [signalA flattenMap:^RACStream *(id value) {
BOOL filter = (value == nil);
return filter ? [RACSignal empty] :[RACSignal return:value];
}]
(2) 支持串行异步操作。
RACSignal *signal = [RACSignal return:@"http://xx.com/a"];
RACSignal *getSignal = [signal flattenMap: ^RACStream *(NSString *url) {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
return [NSURLConnection rac_sendAsynchronousRequest:request];
}];
RACSignal *jsonSignal = [getSignal flattenMap: ^RACStream *(NSData *data) {
NSError *error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
return error == nil ? [RACSignal return: result] : [RACSignal error: error];
}];
RACSignal *getItemSignal = [jsonSignal flattenMap: ^RACStream *(NSDictionary *value) {
if (![value isKindOfClass:[NSDictionary class]] || value[@"data.url"] == nil) {
return [RACSignal error:someError];
}
NSURLRequest *anotherRequest = [NSURLRequest requestWithURL:
[NSURL URLWithString:value[@"data.url"]]];
return [NSURLConnection rac_sendAsynchronousRequest:anotherRequest];
}];
(3)bind相关
4、RAC很多函数基层都是通过bind来实现的(bind是一个十分重要的函数),FlattenMap实现也是通过bind实现,相当于是中间层,上层会基于FlattenMap封装提供map等函数,供使用者调用,有时也直接调用FlattenMap。
5、bind函数的简单实现:
原理讲解:
(1)在最外层创建一个信号,并返回值外界
(2)订阅原始信号
(3)在内部根据传入的block和原始信号的值x,创建一个信号,并由最外层的订阅者来订阅。
(4) 将原始信号产生值、error、complet全部传给最外层订阅者。
6、bind函数代码示例:
//bind 简单实现
- (RACSignal *)bindSample:(RACStreamBindBlock (^)(void))block {
//1、在最外层创建信号,并返回。
RACSignal *newSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
RACStreamBindBlock bindBlock = block();
RACSignal *selfSignal;
//2、订阅原始信号
[self subscribeNext:^(id x) {
BOOL stop = NO;
//3、根据原始信号的信号值,生成一个新生成一个信号。
RACSignal *signal = (RACSignal *)bindBlock(x,&stop);
//3.1、判断信号是否存在和是否停止,如果不存在,直接将消息交给最外层订阅者
if(signal == nil || stop == NO) {
[subscriber sendCompleted];
}
else { //3.2、对新创建的信号进行订阅,并将值传递给最外层的订阅者
[signal subscribeNext:^(id x) {
[subscriber sendNext:x];
} error:^(NSError *error) {
[subscriber sendError:nil];
} completed:^{
//do nothing
}];
}
} error:^(NSError *error) {
[subscriber sendError:nil];
} completed:^{
[subscriber sendCompleted];
}];
return nil; //return nil
}];
return newSignal;
}
FlattenMap 与 Map 对比(简单做下对比,详细内容,可在查阅相关资料)
1、block参数返回值:
- Map:
block参数返回的是id类型的值
- FlattenMap:
返回的是signal。
2、内部实现:
- Map的内部实现:
实际上是通过FlattenMap实现的。
- FlattenMap内部实现:
是基于bind函数来完成的,上面有bind的简单实现。
3、应用:
- FlattenMap通常用于
高阶信号
。- Map通常用于
一维信号
。