RAC(Part2:SideEffect)

作者: 快乐的小问酱 | 来源:发表于2014-11-30 21:58 被阅读928次

    函数编程里一切计算都是为了求值,没有副作用是一个显著地特征。从实用角度出发,RAC引入了副作用。

    Subject

    作为一种“可变”(可变值就是一种副作用,函数�编程里一切值都是不可变的,也就没有变量的概念)的Signal,你可以控制它的值,它就是观察者模式中的Subject。

    RACSubject *animals = [RACSubject subject];
    [animals subscribeNext:^(id nextObject) {
      NSLog(@"%@", nextObject);
    }];
    [animals sendNext:@"cat"];
    

    Multicast Connection (publish, multicast, replay)

    Signal的副作用一般是在subscribe的时候发生的,并且每次subscribe都会发生,这样很多时候并不是所期望的,例如一个网络操作,被subscribe多次也只执行一次,那么我们就需要将这些订阅连接(connection)起来,也就是多播。

    使用publish连接:

    RACSignal *signal = [[RACSignal return:@"hello" ] doNext:^ (id nextValue) {
      NSLog(@"nextValue:%@", nextValue);
    }];
    RACMulticastConnection *connection = [signal publish];
    [connection.signal subscribeNext:^(id nextValue) {
      NSLog(@"First %@", nextValue);
    }];
    [connection.signal subscribeNext:^(id nextValue) {
      NSLog(@"Second %@", nextValue);
    }];
    [connection connect];
    

    这段代码的输出是:

    2014-11-30 15:11:14.711 racdemo[7416:303] nextValue:hello
    2014-11-30 15:11:14.712 racdemo[7416:303] First hello
    2014-11-30 15:11:14.712 racdemo[7416:303] Second hello
    

    connection connect之后,signal开始发送第一个值,如果connection比subscribe先执行,那么订阅就收不到任何的值。所以可以将信号connect到一个replay subject:

    RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
    [connection connect];
    [connection.signal subscribeNext:^(id nextValue) {
      NSLog(@"First %@", nextValue);
    }];
    [connection.signal subscribeNext:^(id nextValue) {
      NSLog(@"Second %@", nextValue);
    }];
    

    其实最简单的做法是使用replay:

    RACSignal *replaySignal = [signal replay];
    [replaySignal subscribeNext:^(id nextValue) {
      NSLog(@"First %@", nextValue);
    }];
    [replaySignal subscribeNext:^(id nextValue) {
      NSLog(@"Second %@", nextValue);
    }];
    

    publish, multicast和replay这几个操作其实都是同一个概念:

    - (RACMulticastConnection *)publish {
      RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
      RACMulticastConnection *connection = [self multicast:subject];
      return connection;
    }
    
    - (RACMulticastConnection *)multicast:(RACSubject *)subject {
      [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
      RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
      return connection;
    }
    
    - (RACSignal *)replay {
      RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"[%@] -replay", self.name];
    
      RACMulticastConnection *connection = [self multicast:subject];
      [connection connect];
    
      return connection.signal;
    }
    

    这里还有一个cold/hot signal的说法,signal默认是cold的,在每次subscribe的时候才会工作;当一个connection建立之后,这个signal就是hot的,在订阅之前已经处于活动状态。

    Command

    对于UI组件,例如一个按钮来说,点击的时候要引起副作用。RAC使用了RACCommand�,方便封装这种副作用。

    self.ClickMe.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id input) {
      NSLog(@"button pressed");
      return [RACSignal empty];
    }];
    

    上面的例子并不能很好的说明RACCommand的本质,一个较为完备的例子:

    self.ClickMe.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id input) {
      RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [subscriber sendNext:@"doing something"];
          [subscriber sendCompleted];
        });
        return nil;
      }];
      return signal;
    }];
    [self.ClickMe.rac_command.executionSignals subscribeNext:^(id doSomethingSignal) {
      NSLog(@"button pressed, let's do something");
      [doSomethingSignal subscribeCompleted:^{
        NSLog(@"done!");
      }];
    }];
    

    signalBlock是一个返回signal的动作,这个动作在按钮被点击的时候执行,返回的signal连接一个RACReplaySubject,然后再executionSignal上订阅。

    另外,在sendCompleted之前,按钮处于禁用状态。

    每次执行动作都会发送一个新的signal,在executionSignals的next中注册这个signal的完成,而不是注册executionSignals的完成,事实上,它不会完成,因为它是代表了这个按钮可能被点击的序列。

    相关文章

      网友评论

      • 超_iOS:RACSignal 该用什么修饰符修饰啊

      本文标题:RAC(Part2:SideEffect)

      本文链接:https://www.haomeiwen.com/subject/xelgtttx.html