A co-worker recently asked me about the difference between -replay-replayLast, and -replayLazily in the ReactiveCocoa library. I had a vague understanding of the three but was not able to confidently explain the difference, so I thought I would look into it further.

I found the header documentation to be difficult to understand if you don’t have a good understanding of RACReplaySubject and RACMulticastConnection, so I’m going to try to explain the replay methods without getting into those underlying concepts.

Subscribing to a Signal

With a “normal” RACSignal each subscription to the signal causes the subscription code to be executed again, and the subscriber only receives values that are sent after the subscription is made. I think it is easiest to show this in two different examples.

The first example shows how the subscription code gets re-executed on each subscription.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  __block int num = 0;
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);
}];

Running this example will produce:

1
2
3
4
5
6
7
  Start subscriptions
Increment num to: 1
S1: 1
Increment num to: 2
S2: 2
Increment num to: 3
S3: 3

As you can see, each subscription causes num to be incremented. Also note that num is not incremented until a subscription is made. In this way, a normal RACSignal can be thought of as lazy, as it doesn’t do any work until it has a subscriber.

Our second example shows how each subscriber only receives the values that are sent after their subscription is added.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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);
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

In many cases this is the desired behavior. But in some cases, you don’t want the subscription code to be re-executed, e.g. a subscription makes a request to a web service and there are multiple listeners that need to be updated when the result comes in. Or maybe you want to get the history of values that have been sent on the signal prior to a subscription. This is where -replay-replayLast, and -replayLazily can be used.

Subscribing to a -replay Signal

The -replay convenience method returns a new signal that, when subscribed to, will immediately send the subscriber the entire history of values that have come through the source signal, without re-executing the source signal’s subscription code. The subscriber will still receive all future values from the signal just as it would from a normal signal.

The first example shows how the subscription code is not re-executed upon new subscriptions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  __block int num = 0;
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);
}];
1
2
3
4
5
  Increment num to: 1
Start subscriptions
S1: 1
S2: 1
S3: 1

This time the num integer is incremented immediately, before there are even any subscribers. And it is only incremented once, meaning that the subscription code is only been executed a single time, regardless of how many subscribers the signal has.

The second example shows how each new subscriber receives the full history of the signal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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);
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

Even though S3 subscribed after all of the values had been sent, it still received all of the values.

Subscribing to a -replayLast Signal

The -replayLast convenience method returns a new signal that, when subscribed to, will immediately send the subscriber the most recent value that comes through the source signal, without re-executing the source signal’s subscription code. The subscriber will then receive all future values from the signal just as it would from a normal signal.

For the first example, there is no difference between -replayLast and -replay so I won’t bother showing it again.

The second example illustrates how only the most recent value is provided to a new subscriber.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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);
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

The -replayLazily convenience method returns a new signal that, when subscribed to, will immediately send the subscriber the entire history of values that have come through the source signal, without re-executing the source signal’s subscription code. The difference between -replayLazily and -replay is that -replayLazily will not subscribe to the source signal until something subscribes to the newly created signal. This is opposed to the behavior of -replay and -replayLast, which subscribe to the source signal immediately upon being called.

The first example illustrates this difference. Note how the “Increment num to: 1” message does not appear until after the first subscription. With -replay (and -replayLast) the same message appears before the first subscription.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  __block int num = 0;
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
num++;
NSLog(@"Increment num to: %i", num);
[subscriber sendNext:@(num)];
return nil;
}] replayLazily];
 
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);
}];
1
2
3
4
5
Start subscriptions
Increment num to: 1
S1: 1
S2: 1
S3: 1

And the second example shows that the full history is sent to any new subscribers, just like with -replay.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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);
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

Summary

ReactiveCocoa provides three convenience methods for allowing multiple subscribers to the same signal, without re-executing the source signal’s subscription code, and to provide some level of historical values to later subscribers. -replay and -replayLast both make the signal hot, and will provide either all values (-replay) or the most recent (-replayLast) value to subscribers. -replayLazily returns a cold signal that will provide all of the signal’s values to subscribers.

转:RAC中比较replay, replayLast, and replayLazily的更多相关文章

  1. ReactiveCocoa比较区分replay, replayLast和replayLazily

    一直搞不清楚replayLazily和replay的区别可以直接跳到最后看. 原文:http://spin.atomicobject.com/2014/06/29/replay-replaylast- ...

  2. Oracle 10g RAC中的DRM问题及关闭

    在RAC环境中,Oracle使用GRD(Global Resource Service)来记录各个RAC节点的资源信息,具体通过GCS(Global Cache Service)和GES(Global ...

  3. rac中 kull session会话脚本

    方法:ALTER SYSTEM KILL SESSION '80, 6, @2';  --<= 80 sid,6 serial#,@2 inst_id kill session 脚本如下:sel ...

  4. 这里的*号实际表示就是RAC中所有实例都使用

    您的位置: ITPUB个人空间 » cc59的个人空间 » 日志 发布新日志 我的日志我的足迹我的收藏 unix/linuxHA随笔backup&restoreperformance tuni ...

  5. 使用OpenFiler来模拟存储配置RAC中ASM共享盘及多路径(multipath)的测试

    第一章 本篇总览 之前发布了一篇<Oracle_lhr_RAC 12cR1安装>,但是其中的存储并没有使用多路径,而是使用了VMware自身提供的存储.所以,年前最后一件事就是把多路径学习 ...

  6. 详解 RAC 中各种IP和监听的意义

    一.SCAN 概念 SCAN(Single Client Access Name)是 Oracle从11g R2开始推出的,客户端可以通过 SCAN 特性负载均衡地连接到 RAC数据库 SCAN 最明 ...

  7. 关于Oracle RAC中SCN原理和机制的探索

    今天看书时看到了关于RAC中SCN的问题,为了进一步搞清楚其内部原理和机制,对该问题进行了广泛的查阅和搜索,遗憾的是,可以参考的资料很少,网上大部分是人云亦云的帖子,其中,详细介绍其内部原理和机制的资 ...

  8. Oracle 11G R2 RAC中的scan ip 的用途和基本原理【转】

    Oracle 11G R2 RAC增加了scan ip功能,在11.2之前,client链接数据库的时候要用vip,假如你的cluster有4个节点,那么客户端的tnsnames.ora中就对应有四个 ...

  9. 转 rac中并行 PARALLEL 的设置

    sample 1: rac中并 行的设置 https://blog.csdn.net/wll_1017/article/details/8285574 我们的生产库一般在节点一上的压力比较大,在节点二 ...

随机推荐

  1. Java第一次试验

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计   班级:1352       姓名:朱国庆   学号:20135237 成绩:             ...

  2. 每日scrum(1)

    今天又正式开始了第二个冲刺周期,计划十天,主要需要改进的地方包括UI界面,还有一些细节的把握. 今天出现的主要问题有:在讨论UI界面风格的时候,小组内部意见不统一,对UI界面的创作流程不熟悉,以及难度 ...

  3. Sprint11

    进展:基本设置和显示已经完成,然后是可以通过长按事件弹出对话框可以进行停用.修改.取消该事件提醒的实现,通过触发动作跳转到各个部分页面.

  4. Beta冲刺 (6/7)

    队名:天机组 组员1友林 228(组长) 今日完成:修改代码 明天计划:封装代码 剩余任务:优化网络通讯机制 主要困难:暂无 收获及疑问:暂无 组员2方宜 225 今日完成:优化了一部分活动,调整了界 ...

  5. 09_Java面向对象_第9天(类、封装)_讲义

    今日内容介绍 1.面向对象思想 2.类与对象的关系 3.局部变量和成员变量的关系 4.封装思想 5.private,this关键字 6.随机点名器 01面向对象和面向过程的思想 A: 面向过程与面向对 ...

  6. Enterprise Library 3.1 参考源码索引

    http://www.projky.com/entlib/3.1/Microsoft/Practices/EnterpriseLibrary/AppSettings/Configuration/Des ...

  7. mac下面安装redis

    本文只记录了在homebrew下面安装redis的过程,过程比较简单,作为自己以后翻阅用吧, 首先安装homebrew,打开终端,在终端下面允许下面的命令(不要用root用户): /usr/bin/r ...

  8. 获取php版本

    phpversion()函数可以获取版本 version_compare可以比较两个版本 mixed version_compare ( string $version1 , string $vers ...

  9. [百度贴吧]10GB 通信线缆

    现在,即使光纤通信能够带来最低延迟的优势,但是许多IT部门依然在10G以太网(10G bE)中使用铜缆布线,来实现交换机和交换机或者和服务器之间的连接.目前主要有两种主要的铜缆布线技术应用在10 Gb ...

  10. vue开发 ES5——> ES6设置