贴源码:

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. [cocos2d]场景切换以及切换进度显示

    本文主要分两个部分叙述,第一是场景切换,第二是场景切换的进度显示. 一.场景切换 参考learn-iphone-and-ipad-cocos2d-game-development 第五章内容 coco ...

  2. 转载:遍历Map的四种方法

    http://www.cnblogs.com/kristain/articles/2033566.html 遍历Map的四种方法 public static void main(String[] ar ...

  3. wcf中netTcpBinding的元素构成

    <security> of <netTcpBinding> <transport> of <netTcpBinding> <message> ...

  4. bzoj1899

    显然如果只有一个窗口,是一道贪心的题目,直接让吃饭慢的排在前面即可 两个窗口的话,我们还是根据这个原则 先对吃饭时间降序排序,然后这是一个dp 假如设当前处理到第i个人,当在窗口1的打饭时间确定了,窗 ...

  5. BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3196 可以处理区间问题的平衡树. 3196: Tyvj 1730 二逼平衡树 Time Lim ...

  6. BZOJ3156: 防御准备

    3156: 防御准备 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 442  Solved: 210[Submit][Status] Descript ...

  7. JBPM4.4部署到tomcat6异常解决办法

    java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.ser ...

  8. uploadify上传图片(限制最多五张)

    项目中遇到图片上传的情况,好多都是使用服务器上传控件进行上传的,很是不爽. 然后在网上找到了uploadify的方法,自己总结和修改后分享给大家. 项目文档预览: 1.引用原有css和js    &l ...

  9. 【ACM/ICPC2013】线段树题目集合(一)

    前言:前一段时间在网上找了一个线段树题目列表,我顺着做了一些,今天我把做过的整理一下.感觉自己对线段树了解的还不是很深,自己的算法能力还要加强.光练代码能力还是不够的,要多思考.向队友学习,向大牛学习 ...

  10. admin-openrc

    #!/bin/bash # To use an Openstack cloud you need to authenticate against keystone, which # returns a ...