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

  • 相关阅读:
    ftp命令行敲不了
    转载 vsftpd安装
    ftp上传不了故障
    mysql导入数据方法和报错解决
    time使用方法
    python 进程Queue
    python 进程事件
    python 进程信号量
    python 进程锁
    python 守护进程
  • 原文地址:https://www.cnblogs.com/codetime/p/6264350.html
Copyright © 2020-2023  润新知