前言
之前我分析了一下源码并且用自己理解的伪代码来实现了这种信号简单的传递流程,并且在说到subject父子的时候我们留下了一个小疑问,的回掉触发时机是在订阅的时候,这样的操作会导致创建时候的didscriberblock被调用好几次,所以引发了人们对于signal优化的思考。
冷信号&热信号
冷信号和热信号的概念我第一次为了加深自己的印象在一片文章中,文章中只是解释了表面意思,个人认为没有考虑到本质。后来发现了美团大众点评技术团队的文章,第一次看的时候是在没有看任何源码的情况下看的,当时真的是一脸懵逼,后来看了下基本的源码重新看了下他们的文章,就觉得通俗易懂了。
(更新一下,我的racsignal的文章中说到了是rac作者创建出的冷热信号概念是不对的,他只是在文章中说出了signal对部分副作用的影响,作者只提到了副作用的概念,冷热信号概念来自.NET的RX)
差异化的概念
1.冷信号是指当我们订阅者订阅了这个信号,我们的信号才开始发送消息。并且冷信号只针对于一个订阅者不支持多个订阅者同接收。
2.热信号是指无论你有没有订阅者,只要你发送了信号并且我这个信号存在,我就会进行推送。并且热信号支持多个订阅者同时接收。对号入座
看完上边冷热信号概念,我们对号入座一波首先我们能确定的就是:
1.RacSignal就是冷信号,可以做个实验
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
}];
return nil;
}];
[signal subscribeNext:^(id x) {
NSLog(@"subscriber1: %@", x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"subscriber2: %@", x);
}];
控制台打印:
01:02:53.220464+0800 RACOne[52411:2578142] subscriber1: 1
01:02:53.220684+0800 RACOne[52411:2578142] subscriber1: 2
01:02:53.220863+0800 RACOne[52411:2578142] subscriber2: 1
01:02:53.221321+0800 RACOne[52411:2578142] subscriber2: 2
可以看出他的确完全符合冷信号的概念。首先订阅是这个发送的触发时机,只有一个block订阅了他才会发送信号并且产生订阅回掉。这一系列也解释了为什么只有订阅了才会发送信号的原因。其次发送信号都是在订阅时候调用的而订阅者单一单线程操作所以才会执行完第一个订阅者在执行第二个订阅者。
- RacSubject父子是热信号。
注意一下这里为什么racreplaysubject也是热信号,虽然他们也是订阅了才会发送信号,但是他们的关注点是时间这条线,支持多订阅者同时发送,而signal关注的是订阅这条线,单订阅者订阅
实验如下:
RACSubject *subject = [RACSubject subject];
RACReplaySubject *replaySubject = [RACReplaySubject subject];
[subject sendNext:@"1"];
[replaySubject sendNext:@"1"];
[[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
[subject sendNext:@"2"];
[replaySubject sendNext:@"2"];
}];
[subject subscribeNext:^(id x) {
NSLog(@"subscriber1: %@", x);
}];
[subject subscribeNext:^(id x) {
NSLog(@"subscriber2: %@", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Replaysubscriber1: %@", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Replaysubscriber2: %@", x);
}];
控制台:
01:27:03.229905+0800 RACOne[52618:2590686] Replaysubscriber1: 1
01:27:03.230147+0800 RACOne[52618:2590686] Replaysubscriber2: 1
01:27:04.230362+0800 RACOne[52618:2590686] subscriber1: 2
01:27:04.230538+0800 RACOne[52618:2590686] subscriber2: 2
01:27:04.230755+0800 RACOne[52618:2590686] Replaysubscriber1: 2
01:27:04.230869+0800 RACOne[52618:2590686] Replaysubscriber2: 2
副作用
// racSiganl创建时对于副作用的阐述
Note:** The `didSubscribe` block is called every time a new subscriber
subscribes. Any side effects within the block will thus execute once for each
subscription, not necessarily on one thread, and possibly even
simultaneously!
rac是一套基于cocoa的FRP框架,FRP又称之为函数式响应编程,既然说到函数,假如是纯函数,外部传入只在函数中有改变而不对外部做出修改,但是针对于OOP中肯定包含副作用的地方。具体副作用是什么,产生在哪:
- 函数执行过程中,修改了外部的变量,例如在一个函数中修改了类中的属性,常量。例:在OC的block修改了类中的属性就是一个副作用。
- 函数处理过程中包含触发事件,代理,block,notification等也会有函数副作用的存在
- 函数处理过程中,受到锁的影响也属于。
- 函数中针对传入指针地址也属于,内部修改后对外部修改。
那么在编程中,这些场景基本都是编程中常见的,就是你用户点到了哪里触发了事件都属于副作用。可以说在日常编程中,副作用基本都存在,也可以这么说我们的编程就是为了产生副作用。
那么如何才能避免副作用呢?副作用又会在什么场景发挥出他们邪恶的一面呢?冷热信号和副作用有什么关系呢?