zoukankan      html  css  js  c++  java
  • ReactiveCocoa 中signal(operation) then与doNext的区别

    贴源码:

    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:

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

    /// then subscribes to a new signal.

    doNext:

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

    /// the signal.

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

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

    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来做接下来的事

  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/codetime/p/6264350.html
Copyright © 2011-2022 走看看