组合

组合变换是一组多元变换形式,每次变换是由多个节点出发,经过相互计算最终向其下游节点进行传播。在实现的过程中,通常需要借助一个对象把多个变换管理起来,例如源码中的 EasyReact/Core/NodeTransforms/EZRCombineTransformGroup.h。下面介绍下全部的组合变换形式。

combine

响应式编程经常会使用 a := b + c 来举例,意图是当 b 或者 c 的值发生变化的时候,a 会保持两者的加和。那么在响应式库 EasyReact 中,我们是怎样体现的呢?就是通过 EZRCombine-mapEach 操作:

  1. EZRMutableNode<NSNumber *> *nodeA = [EZRMutableNode value:@1];
  2. EZRMutableNode<NSNumber *> *nodeB = [EZRMutableNode value:@2];
  3. EZRNode<NSNumber *> *nodeC = [EZRCombine(nodeA, nodeB) mapEach:^NSNumber *(NSNumber *a, NSNumber *b) {
  4. return @(a.integerValue + b.integerValue);
  5. }];
  6. nodeC.value; // <- 1 + 2 = 3
  7. nodeA.value = @4;
  8. nodeC.value; // <- 4 + 2 = 6
  9. nodeB.value = @6;
  10. nodeC.value; // <- 4 + 6 = 10

merge

合并操作其实很好理解,合并多个节点作为上游,当任何一个节点有新值的时候,下游都会更新:

  1. EZRMutableNode<NSNumber *> *nodeA = [EZRMutableNode value:@1];
  2. EZRMutableNode<NSNumber *> *nodeB = [EZRMutableNode value:@2];
  3. EZRNode<NSNumber *> *nodeC = [nodeA merge:nodeB];
  4. // 首次合并会以最后有值的节点的值作为下游节点的初始值
  5. nodeC.value; // <- 2
  6. nodeA.value = @3;
  7. nodeC.value; // <- 3
  8. nodeB.value = @4;
  9. nodeC.value; // <- 4

zip

拉链操作是这样的一种操作:它将多个节点作为上游,所有的节点的第一个值放在一个元组里,所有的节点的第二个值放在一个元组里……以此类推,以这些元组作为值的就是下游。它就好像拉链一样一个扣着一个:

  1. EZRMutableNode<NSNumber *> *nodeA = [EZRMutableNode value:@1];
  2. EZRMutableNode<NSNumber *> *nodeB = [EZRMutableNode value:@2];
  3. EZRNode<EZTuple2<NSNumber *, NSNumber *> *> *nodeC = [nodeA zip:nodeB];
  4. [[nodeC listenedBy:self] withBlock:^(EZTuple2<NSNumber *, NSNumber *> *tuple) {
  5. NSLog(@"接收到 %@", tuple);
  6. }];
  7. nodeA.value = @3;
  8. nodeA.value = @4;
  9. nodeB.value = @5;
  10. nodeA.value = @6;
  11. nodeB.value = @7;
  12. /* 打印如下:
  13. 接收到 <EZTuple2: 0x60800002b140>(
  14. first = 1;
  15. second = 2;
  16. last = 2;
  17. )
  18. 接收到 <EZTuple2: 0x60800002ac40>(
  19. first = 3;
  20. second = 5;
  21. last = 5;
  22. )
  23. 接收到 <EZTuple2: 0x600000231ee0>(
  24. first = 4;
  25. second = 7;
  26. last = 7;
  27. )
  28. */

其过程如下:

  1. nodeA: -------1-------3-------4---------------6
  2. |
  3. |
  4. |
  5. |
  6. nodeB: -------2-----------------+-----5--------+------7
  7. | | |
  8. nodeC: -----(1,2)-------------------(3,5)-----------(4,7)