ReactiveCocoa技术讲解-第三讲信号的高阶操作

SwitchToLatest:

1、当新的值信号产生的时候,立即订阅最新的值信号。同时把前一个值信号关闭掉,取消订阅。
2、降维后新信号的结束时间:取决于信号最后一个值信号的结束时间。
3、降维后新信号的异常处理:只要有一个值信号产生异常,就会传递下来。
4、图示:

switchToLatest.png

5、应用示例:后续添加,暂时在项目中未摘出 。

//敬请期待
if/then/else

1、作用描述:每次为Yes是则从信号A的第一个值开始读取信号,知道下一个值为NO时,则从信号B的第一个值开始读取信号。依次反复。每次读取从是从相应信号的第一个值开始。
2、图示:

if:then:else.png

3、if/then/else的本质:
实质就是先把boolSignal做一个map操作,当为yes时,返回trueSignal,当为No时,返回falseSignal,所以最终我们得到一个高阶信号。详情见下图:
if:then:else实质.png

4、使用示例:

Flatten

1、扁平,通常用于高阶信号的降阶操作
2、图示:


flatten.png
Flatten:(NSUInteger)

1、作用:同Flatten作用一致,只不过这里设定了对应参数值。
2、参数值:作用是设定当前栈中的信号数量。flatten对信号做降阶操作时,内部会维护两个栈:当前栈等待栈
(2.1)当前栈中用来存放正在订阅的信号,当前栈中的信号只能等信号完成后信号才会从栈中退出。
(2.2)等待栈中用来存放 已经产生,但是还没有进行订阅处理的信号。
3、图示:

Flatten变形.png

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<RACSubscriber> 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通常用于一维信号
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,431评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,637评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,555评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,900评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,629评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,976评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,976评论 3 448
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,139评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,686评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,411评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,641评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,129评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,820评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,233评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,567评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,362评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,604评论 2 380

推荐阅读更多精彩内容