贴源码:

doNext:实现的主要源代码

return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
return [self subscribeNext:^(id x) {
block(x);
[subscriber sendNext:x];
} error:^(NSError *error) {
[subscriber sendError:error];
} completed:^{
[subscriber sendCompleted];
}];
}] setNameWithFormat:@"[%@] -doNext:", self.name];

then:实现的主要源代码
1、
- (RACSignal *)then:(RACSignal * (^)(void))block {
NSCParameterAssert(block != nil);

return [[[self
ignoreValues]
concat:[RACSignal defer:block]]
setNameWithFormat:@"[%@] -then:", self.name];
}
2、
- (RACSignal *)ignoreValues {
return [[self filter:^(id _) {
return NO;
}] setNameWithFormat:@"[%@] -ignoreValues", self.name];
}
3、
- (instancetype)filter:(BOOL (^)(id value))block {
NSCParameterAssert(block != nil);

Class class = self.class;

return [[self flattenMap:^ id (id value) {
if (block(value)) {
return [class return:value];
} else {
return class.empty;
}
}] setNameWithFormat:@"[%@] -filter:", self.name];
}

从上面doNext与then的代码比较
从实现上看有几点:

   a、doNext是在当前信号执行的任务完成后,将当前任务的结果传递给新的signal,而then:则是执行完后不会把当前的singal的结果网下传,而是生成了一个empty这个signal接着让这个empty signal来处理接下来的事。(在信号本身订阅完后处理接下来的操作)

   then是直接创建一个signal并让这个singal来转发当前消息执行后的结果, doNext到最后是flattenMap,flattenMap则是通过bind的方式来实现的,而bind的方法中有介绍其功能要求(处理完之前的订阅后生成一个empty信号然后在empty信号中执行接下来的操作。):
/*
* -bind: should:
* 
* 1. Subscribe to the original signal of values.
* 2. Any time the original signal sends a value, transform it using the binding block.
* 3. If the binding block returns a signal, subscribe to it, and pass all of its values through to the subscriber as they're received.
* 4. If the binding block asks the bind to terminate, complete the _original_ signal.
* 5. When _all_ signals complete, send completed to the subscriber.
* 
* If any signal sends an error at any point, send that to the subscriber.
*/
bind:其中2,3两点比较特别:
在任一时刻元信号收到一个处理值的时候bindblock会做一个转换处理;
bind将一个signal作为一个bindblock中的一个返回值并且订阅这个signal;

c、资源释放角度:
doNext:RACCompoundDisposable *disposable add RACDisposable *schedulingDisposable
then:RACCompoundDisposable *disposable add RACSerialDisposable *selfDisposable
d、使用doNext和then:

 
resetBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
@strongify(self)

RACSignal *signal = [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:nil];
[subscriber sendCompleted];
return nil;
}] doNext:^(id x) {
NSLog(@"next");

}]doNext:^(id x) {
NSLog(@"next1");
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"then");
[subscriber sendNext:nil];
[subscriber sendCompleted];
return nil;
}];
}];
return signal;
// }];
print:
    next
    next1
    then

resetBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
@strongify(self)

RACSignal *signal = [[[[RACSignal empty] doNext:^(id x) {
NSLog(@"next");

}]doNext:^(id x) {
NSLog(@"next1");
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"then");
[subscriber sendNext:nil];
[subscriber sendCompleted];
return nil;
}];
}];
return signal;
// }];
}] ;
print:
   then

then 执行的时候会忽略之前一个信号的结果,sendNext则会保留结果传给下个信号。

这样如果通过doNext:执行的话,如果执行的信号结果是一个empty那么doNext是不能够执行下去的。

而then的之前执行是在调用 ignoreValues 创建一个新的信号来接着执行,所以then能够确保下一步执行

提一下ignoreValues,ignoreValues这个方法最终实现是落在bind signal方法上,而bind这个方法实际上是一个串,通过里面的addSignal和completeBlock来完成。也就是说可以在doNext执行完之前都是信号依赖信号的形式,但是这种信号依赖机制不能够确保传出的不是empty信号,所以这种方式有可能会中断

也就是说then并不会把doNext的操作给忽略掉,只会把doNext的传出参数给忽略,同时doNext不能处理前一个signal为empty的情况,而then不管前一个signal是否是空的都可以接着执行

最后再看一下then和doNext的方法说明

then:

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400 }
span.s1 { }

/// Ignores all `next`s from the receiver, waits for the receiver to complete,

/// then subscribes to a new signal.

doNext:

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400 }
span.s1 { }

/// Do the given block on `next`. This should be used to inject side effects into

/// the signal.

前者忽略接收者的消息,并等待接收者执行完后,再订阅一个新的信号。

后者是将一个block作为副作用注入到signal中。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
span.s1 { }

2017-01-09 17:26:23.355 HXViewDataBinding[2330:1268857] <RACDynamicSignal: 0x6000004269e0> name: 

2017-01-09 17:26:23.355 HXViewDataBinding[2330:1268857] <RACDynamicSignal: 0x6180002241a0> name: 

可以看到side effect其实也是通过createSignal的形式来完成的,只是在createsignal中完成了当前消息的转发并把消息结果给新的signal并让新的signal来做接下来的事

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #31595d }
span.s1 { color: #ba2da2 }
span.s2 { }
span.s3 { color: #4f8187 }
span.s4 { color: #31595d }
span.s5 { color: #703daa }
span.s6 { color: #000000 }
span.s7 { color: #d12f1b }
span.Apple-tab-span { white-space: pre }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #78492a }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; min-height: 13.0px }
p.p4 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #ba2da2 }
p.p5 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #31595d }
span.s1 { }
span.s2 { color: #4f8187 }
span.s3 { color: #ba2da2 }
span.s4 { color: #000000 }
span.s5 { color: #31595d }
span.s6 { color: #d12f1b }
span.Apple-tab-span { white-space: pre }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #ba2da2 }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
span.s1 { }
span.s2 { color: #4f8187 }
span.s3 { color: #ba2da2 }
span.s4 { color: #31595d }
span.s5 { color: #000000 }
span.Apple-tab-span { white-space: pre }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #78492a }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; min-height: 13.0px }
p.p4 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #31595d }
span.s1 { }
span.s2 { color: #ba2da2 }
span.s3 { color: #000000 }
span.s4 { color: #3e1e81 }
span.s5 { color: #31595d }
span.s6 { color: #d12f1b }
span.s7 { color: #4f8187 }
span.Apple-tab-span { white-space: pre }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400 }
span.s1 { }
span.Apple-tab-span { white-space: pre }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 }
span.s1 { }

ReactiveCocoa 中signal(operation) then与doNext的区别的更多相关文章

  1. ReactiveCocoa 中 RACSignal 是怎样发送信号

    前言 ReactiveCocoa是一个(第一个?)将函数响应式编程范例带入Objective-C的开源库.ReactiveCocoa是由Josh Abernathy和Justin Spahr-Summ ...

  2. ReactiveCocoa 中 RACSignal 是如何发送信号的

    https://juejin.im/post/5829f4c3570c350063c436ac 前言 ReactiveCocoa是一个(第一个?)将函数响应式编程范例带入Objective-C的开源库 ...

  3. PHP中new static()与new self()的区别异同分析

    本文实例讲述了PHP中new static()与new self()的区别异同,相信对于大家学习PHP程序设计能够带来一定的帮助. 问题的起因是本地搭建一个站.发现用PHP 5.2 搭建不起来,站PH ...

  4. ScheduledExecutorService中scheduleAtFixedRate方法与scheduleWithFixedDelay方法的区别

    ScheduledExecutorService中scheduleAtFixedRate方法与scheduleWithFixedDelay方法的区别 ScheduledThreadPoolExecut ...

  5. [转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别

    1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会 ...

  6. angularjs中provider,factory,service的区别和用法

    angularjs中provider,factory,service的区别和用法 都能提供service,但是又有差别 service 第一次被注入时实例化,只实例化一次,整个应用的生命周期中是个单例 ...

  7. 正则表达式中的exec和match方法的区别

    正则表达式中的exec和match方法的区别 字符串的正则方法有:match().replace().search().split() 正则对象的方法有:exec().test() 1.match m ...

  8. JOIN关联表中ON,WHERE后面跟条件的区别

    select * from td  left join (select case_id as sup_case_id , count(*) supervise_number from  td_kcdc ...

  9. Java中public,private,protected,和默认的区别

    Java中public,private,protected,和默认的区别 1.private修饰词,表示成员是私有的,只有自身可以访问: 2.protected,表示受保护权限,体现在继承,即子类可以 ...

随机推荐

  1. POP3、SMTP、IMAP和Exchange的区别在哪里?

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:永遇乐链接:http://www.zhihu.com/question/24605584/answer/29039357来源: ...

  2. java学习之线程

    一.线程总述: 线程是java当中一个重要的内容,如果想说线程的话,那我们应该先来讲一下什么是进程. 进程:那么什么是进程呢,进程从字面上来理解就是,正在进行的程序.就比如说我们在windows当中打 ...

  3. linux上TCP connection timeout的原因查找

    linux上TCP connection timeout的原因查找 好久没有写文章了, 今天解决了一个网络连接超时的问题, 记录以备查看. 最近在线上nginx经常出现输出connection tim ...

  4. bzoj1179

    这种tarjan+dp的水题我竟然还WA了两次,要小心! type link=^node;      node=record        po:longint;        next:link; ...

  5. 大白书 209 remember the word

    F - Remember the Word Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Sub ...

  6. CG&Game资源(转)

    cg教程下载: http://cgpeers.com http://cgpersia.com http://bbs.ideasr.com/forum-328-1.html http://bbs.ide ...

  7. JavaScript高级程序设计43.pdf

    事件类型 Web浏览器中有很多事件类型,“DOM3级事件”规定了以下几类事件 UI事件(用户界面),当用户与页面上的元素交互时触发: 焦点事件,当元素获得或失去焦点时触发 鼠标事件,当用户通过鼠标在页 ...

  8. WCF、.Net Remoting、Web Service概念及区别

    此文章主要参考http://www.cnblogs.com/weiweibtm/archive/2013/06/21/3148583.html 参考书籍<WCF全面解析上册>.<WC ...

  9. (DT系列五)Linux kernel 是怎么将 devicetree中的内容生成plateform_device

    Linux kernel 是怎么将 devicetree中的内容生成plateform_device 1,实现场景(以Versatile Express V2M为例说明其过程)以arch/arm/ma ...

  10. 最短路SPFA

    用邻接矩阵a表示一幅图,a[i][j]表示从点i到点j的边长,如果为0则无边.(这是无负边,0边的情况) 这张图有T个点,C条边,要求求出从Ts走到Te的最短路. 用f[i]表示从Ts走到i点的最短路 ...