ReactiveCocoa比较区分replay, replayLast和replayLazily
一直搞不清楚replayLazily和replay的区别可以直接跳到最后看。
原文:http://spin.atomicobject.com/2014/06/29/replay-replaylast-replaylazily/
如果没有对RACReplaySubject和RACMulticastConnection深入研究的话,你将会很难理解它们在头文件中的描述。现在我们不去了解底层原理,用通俗的语言和图表去描述解析这几个方法。
Subscribing to a Signal
对于一个“普通”的信号,每次订阅都将会导致信号中的代码再执行一遍,且该次订阅者仅接收到该次订阅发送出去的值。
第一个例子演示每次订阅都会重新执行订阅代码。
__block int num = ;
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}]; NSLog(@"Start subscriptions"); // Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; // Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; // Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
运行结果如下:
Start subscriptions
Increment num to:
S1:
Increment num to:
S2:
Increment num to:
S3:

可以看到,每次订阅num都在递增,如果不订阅则不会递增。通过这种方式,可以知道信号是懒惰的,如果没有订阅者的话,是不会执行的。
第二个例子演示信号被添加订阅的时候,订阅者是怎么接收发送的值的。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = letters; NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"]; NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"]; NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
运行结果
Subscribe S1 Send A
S1: A Send B
S1: B Subscribe S2 Send C
S1: C
S2: C Send D
S1: D
S2: D Subscribe S3

在很多情况下,这是我们想要的预期结果,不过在某些情况下,你不需要订阅的代码再次被执行。例如订阅 一个向网络服务器发送的请求,当服务器返回数据时,多个监听者需要更新(无论有多少个监听者,请求只发送一下(第一个例子就不满足我们的需求)),或者我们想拿到订阅前信号发送过的值(第二个例子,S2想拿A,B的值或者S3想拿A,B,C,D的值,就不满足我们的需求了)。因此-replay, -replayLast, and -replayLazily应需而生。
Subscribing to a -replay Signal
这个replay方法将返回一个新的信号,当源信号被订阅时,会立即发送给订阅者全部历史的值,不会重复执行源信号中的订阅代码,不仅如此,订阅者还将收到所有未来发送过去的值。
第一个例子演示信号添加新的订阅时,代码是不会再次被执行的。
__block int num = ;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}] replay]; NSLog(@"Start subscriptions"); // Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; // Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; // Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Increment num to:
Start subscriptions
S1:
S2:
S3:

信号首次被订阅时,num立马被递增了,且仅仅递增了一次。这说明了不管有你多个订阅者,订阅代码我只执行了一次。
第二个例子演示每个新添加的订阅者接收到信号中全部的值(不管是之前发出的值还是将来发出的值)。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replay]; NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"]; NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"]; NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1 Send A
S1: A Send B
S1: B Subscribe S2
S2: A
S2: B Send C
S1: C
S2: C Send D
S1: D
S2: D Subscribe S3
S3: A
S3: B
S3: C
S3: D

尽管订阅者S3在所有的值发送之后再订阅,然后还能接收到所有的值。
Subscribing to a -replayLast Signal
这个replayLast返回一个新的信号,当源信号被订阅时,会立即发送给订阅者最新的值,不会重复执行源信号中的订阅代码。订阅者还会收到信号未来所有的值。
对于第一个例子,跟之前replay一样,所以我就不再次演示了。
第二个例子演示如何将最新的值提供给新的订阅者
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replayLast]; NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"]; NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"]; NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1 Send A
S1: A Send B
S1: B Subscribe S2
S2: B Send C
S1: C
S2: C Send D
S1: D
S2: D Subscribe S3
S3: D

Subscribing to a -replayLazily Signal
这replayLazily方法返回一个新的信号,当源信号被订阅时,会立即发送给订阅者全部历史的值,不会重复执行源信号中的订阅代码。跟replay不同的是,replayLazily被订阅生成新的信号之前是不会对源信号进行订阅的(原文写的有点绕,简单来讲 直到订阅时候才真正创建一个信号,源信号的订阅代码才开始执行)。暂时不理解也没事,看下面的代码输出,和注释。
这第一个例子会说明跟replay差异。 注意字符串 “Increment num to: 1”是被订阅了之后才打印显示的。而replay和replayLast没被订阅前就打印了“Increment num to: 1” 这个消息。
__block int num = ;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}] replayLazily]; //跟replay不同的就这么一个地方 NSLog(@"Start subscriptions"); // Subscriber 1 (S1)
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; // Subscriber 2 (S2)
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; // Subscriber 3 (S3)
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
// 帖子滚动起来,跟replay比较一下 Increment num to: 1 的显示顺序。 Start subscriptions // 实际订阅
Increment num to: // 信号开始创建
S1:
S2:
S3:

第二个例子演示将全部历史的值提供给任何新的订阅者,就像replay一样。
RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replayLazily]; NSLog(@"Subscribe S1");
[signal subscribeNext:^(id x) {
NSLog(@"S1: %@", x);
}]; NSLog(@"Send A");
[letters sendNext:@"A"];
NSLog(@"Send B");
[letters sendNext:@"B"]; NSLog(@"Subscribe S2");
[signal subscribeNext:^(id x) {
NSLog(@"S2: %@", x);
}]; NSLog(@"Send C");
[letters sendNext:@"C"];
NSLog(@"Send D");
[letters sendNext:@"D"]; NSLog(@"Subscribe S3");
[signal subscribeNext:^(id x) {
NSLog(@"S3: %@", x);
}];
Subscribe S1 Send A
S1: A Send B
S1: B Subscribe S2
S2: A
S2: B Send C
S1: C
S2: C Send D
S1: D
S2: D Subscribe S3
S3: A
S3: B
S3: C
S3: D

总结一下:
ReactiveCocoa提供了这三个简便的方法允许多个订阅者订阅一个信号,却不会重复执行订阅代码,并且能给新加的订阅者提供订阅前的值。replay和replayLast使信号变成热信号,且会提供所有值(-replay) 或者最新的值(-replayLast) 给订阅者。 replayLazily返回一个冷的信号,会提供所有的值给订阅者。
ReactiveCocoa比较区分replay, replayLast和replayLazily的更多相关文章
- 转:RAC中比较replay, replayLast, and replayLazily
A co-worker recently asked me about the difference between -replay, -replayLast, and -replayLazily i ...
- 一次MVVM+ReactiveCocoa实践
前言 学习MVVM和ReactiveCocoa(简称RAC)也有一段时间了,不过都仅限于看博客,一直对这两个东西很感兴趣,觉得很创新,也一直想找个机会在项目中实践一下,但是还是有一些顾虑,毕竟没有实践 ...
- ReactiveCocoa v2.5 源码解析 之 架构总览
ReactiveCocoa 是一个 iOS 中的函数式响应式编程框架,它受 Functional Reactive Programming 的启发,是 Justin Spahr-Summers 和 J ...
- ReactiveCocoa的冷信号与热信号 探讨
背景 ReactiveCocoa(简称RAC)是最初由GitHub团队开发的一套基于Cocoa的FRP框架.FRP即Functional Reactive Programming(函数式响应式编程), ...
- RACSignal的Subscription深入
ReactiveCocoa是一个FRP的思想在Objective-C中的实现框架,目前在美团的项目中被广泛使用.对于ReactiveCocoa的基本用法,网上有很多相关的资料,本文不再讨论.RACSi ...
- ReactiveCocoa_v2.5 源码解析之架构总览
ReactiveCocoa 是一个 iOS 中的函数式响应式编程框架,它受 Functional Reactive Programming 的启发,是 Justin Spahr-Summers 和 J ...
- 走进ReactiveCocoa的世界
在学习ReactiveCocoa之前,先学习一下概念 ReactiveCocoa 是一套开源的基于Cocoa的FRP框架 .FRP的全称是Functional Reactive Programming ...
- ReactiveCocoa基础知识内容
本文记录一些关于学习ReactiveCocoa基础知识内容,对于ReactiveCocoa相关的概念如果不了解可以网上搜索:RACSignal有很多方法可以来订阅不同的事件类型,ReactiveCoc ...
- ReactiveCocoa应用篇(二)
上一篇介绍了ReactiveCocoa的常用类,已经基本满足项目中的简单应用要求,但是针对复杂的功能还需要其它的类来协同处理.ReactiveCocoa提供了强大的流程处理功能来解决复杂的问题,包括事 ...
随机推荐
- 关于ORACLE DUAL表
1.DUAL表的用途 Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的Select语句块中--查看当前连接用户 SQL> select user from d ...
- DedeCMS调用多说评论系统遇到的一些问题
最近前端笔记加入了多说的评论,因为自带的评论太渣了.过程不是很顺利,把遇到的问题和大家分享下.我用的dedecms,所以使用的是dede的多说评论模块.效果图: 多说官方下载:http://dev.d ...
- MySql文章
转: MySql安全建议 http://www.cnblogs.com/crystal189/p/3492640.html
- 0c-41-ARC下循环引用问题
1.ARC下循环引入问题 一个人拥有一只狗,一只狗拥有一个主人. 当增加d.owner = p;时形成循环引用. 解决方法:一端用strong,一端用weak. 2.ARC下@property参数 A ...
- jquery 动态事件绑定(0512)
jquery动态事件绑定,父元素需为静态元素,(不能是动态生成): $("#parent").on("click","#child",fun ...
- 常见hash算法的原理
散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Hash table,也叫 ...
- NET开发必备工具之-LINQPad
第一步,下载:http://www.linqpad.net/ 第二步,安装 第三步,打开LINQPad 第四步,添加链接 第五步,输入SQL Server,用户名,密码 第六步,点击OK,成功链接 第 ...
- 史上最全的 UIWebview 的 JS 与 OC 交互
来源:伯乐在线 - 键盘风筝 链接:http://ios.jobbole.com/89330/ 点击 → 申请加入伯乐在线专栏作者 其实一直想给大家整理一下JS与OC的交互,但是没有合适的机会,今天借 ...
- SQL Server 表和索引存储结构
在上一篇文章中,我们介绍了SQL Server数据文件的页面类型,系统通过96个字节的头部信息和系统表从逻辑层面上将表的存储结构管理起来,具体到表的存储结构上,SQL Server引入对象.分区.堆或 ...
- Balloon Comes!
Problem Description The contest starts now! How excited it is to see balloons floating around. You, ...