從計(jì)算器到ReactiveCocoa

ReactiveCocoa是github開(kāi)源的一個(gè)函數(shù)式響應(yīng)式編程(FRP)框架

  • 函數(shù)式吶應(yīng)式編程(FRP)

    函數(shù)式響應(yīng)式,這里面包含了兩個(gè)編程風(fēng)格.即函數(shù)式(Functional Programming)和響應(yīng)式(Reactive Programming),這里先介紹函數(shù)式,在說(shuō)函數(shù)式之前先介紹鏈?zhǔn)骄幊?

    • 鏈?zhǔn)骄幊?/p>

      是將多個(gè)操作(多行代碼)通過(guò)點(diǎn)號(hào)(.)鏈接在一起成為一句代碼,使代碼可讀性好。a(1).b(2).c(3),常用框架Masonry.我們的主題是從計(jì)算器到ReactiveCocoa,就拿計(jì)算器為例了。

      @interface CalculatorMaker : NSObject
      @property (nonatomic, assign) int result;
      //加法
      - (CalculatorMaker *(^)(int value))add;
      //減法
      - (CalculatorMaker *(^)(int value))sub;
      //歸0
      - (CalculatorMaker *(^)(void))clean;
      
      - (void)makeCalculator:(void(^)(CalculatorMaker *mark))markBlock;
      @end
      
      @implementation CalculatorMaker
      - (CalculatorMaker *(^)(int value))add {
          return ^CalculatorMaker *(int a) {
              self.result += a;
              return self;
          };
      }
      
      - (CalculatorMaker *(^)(int value))sub {
          return ^CalculatorMaker *(int a) {
              self.result -= a;
              return self;
          };
      }
      
      - (CalculatorMaker *(^)(void))clean {
          return ^CalculatorMaker *(void) {
              self.result = 0;
              return self;
          };
      }
      
      - (void)makeCalculator:(void(^)(CalculatorMaker *mark))markBlock {
          markBlock(self);
      }
      @end
      
      //sample
      CalculatorMaker *calculator = [[CalculatorMaker alloc] init];
      [calculator makeCalculator:^(CalculatorMaker *mark) {
          mark.add(2).sub(1).clean().add(3);
      }];
      NSLog(@"~~~~ value %d",calculator.result);
      /*output
        ~~~~ value 3
      */
      

      這里要問(wèn)一下為什么能通過(guò).操作符連接操作,回想一下.操作符在OC中實(shí)際是防問(wèn)屬性的get和set方法的一種簡(jiǎn)寫.所以我們來(lái)拆開(kāi)

      CalculatorMaker *calculator = [[CalculatorMaker alloc] init];
      [calculator makeCalculator:^(CalculatorMaker *mark) {
          CalculatorMaker *(^tmpAddBlock)(int) = [mark add];
          CalculatorMaker *tmpAddReturn = tmpAddBlock(2);
      
          CalculatorMaker *(^tmpSubBlock)(int) = [tmpAddReturn sub];
          CalculatorMaker *tmpSubReturn = tmpSubBlock(1);
      
          CalculatorMaker *(^tmpCleanBlock)(void) = [tmpSubReturn clean];
          CalculatorMaker *tmpCleanReturn = tmpCleanBlock();
      
          CalculatorMaker *(^tmpAdd2Block)(int) = [tmpCleanReturn add];
          CalculatorMaker *tmpAdd2Return = tmpAdd2Block(3);
      }];
      NSLog(@"~~~~ value %d",calculator.result);
      /*output
        ~~~~ value 3
      */    
      //所以兩者結(jié)果是完全一樣的
      

      接下來(lái)介紹函數(shù)式編程,在介紹這個(gè)之前先介紹兩個(gè)很有意思的概念

      • side effects(副作用)

        副作用是在計(jì)算結(jié)果的過(guò)程中,系統(tǒng)狀態(tài)的一種改變,或是外部世界可觀察的交互作用。比如,更改檔案系統(tǒng),發(fā)送http請(qǐng)求等,只要與function外部環(huán)境發(fā)生交互作用的都是副作用。

      • pure function(純函數(shù))

        定義:相同輸入,永遠(yuǎn)會(huì)得到相同的輸出,而且沒(méi)有任何顯著副作用.

        擴(kuò)展解釋:函數(shù)與外界交互只有唯二通道,參數(shù)、返回值(輸入,輸出)。同時(shí)參數(shù)應(yīng)該是只讀的,函數(shù)不應(yīng)該修改參數(shù)內(nèi)部數(shù)據(jù),以下舉幾個(gè)例子

        //例一:相同輸入,永遠(yuǎn)會(huì)得到相同的輸出,沒(méi)有副作用
        var min = 1;
        var OuterCompareNumber = function(number) {
          return number > min;
        }
        
        var InnerCompareNumber = function(number) {
          var min = 1;
          return number > min;
        }
        //OuterCompareNumber非純函數(shù).min可能會(huì)被外界改變
        //InnerCompareNumber是純函數(shù)
        
        //例二:沒(méi)有任何顯著副作用
        var callRequest = function(url,paramas) {
          return $.getJSON(url, paramas);
        }
        
        var delayCallRequest = function(url,paramas) {
          return function() {
            return $.getJSON(url, paramas);
          }
        }
        
        /*
        callRequest(url, paramas);
        delayCallRequest(url, paramas)();
        callRequest直接返回了一個(gè)http請(qǐng)求,那么這個(gè)是與外界交互,
        返回的結(jié)果有太大的不確定性,所以是impure的函數(shù);
        而delayCallRequest采用了延遲執(zhí)行的方式,返回了一個(gè)函數(shù),
        只有調(diào)用這個(gè)函數(shù)的時(shí)候才會(huì)發(fā)送請(qǐng)求:delayCallRequest(url, params)(),
        但就delayCallRequest而言,傳相同的參數(shù),得到的結(jié)果是一樣的,是相同參數(shù)的函數(shù),
        所以這個(gè)是一個(gè)pure的函數(shù)。
        */
        

        先簡(jiǎn)單了解一下這兩個(gè)概念,下面會(huì)有用到。純函數(shù)有如下好處.
        1.無(wú)狀態(tài),Stateless。線程安全。不需要線程同步。
        2.Pure Function相互調(diào)用組裝起來(lái)的函數(shù),還是Pure Function。
        3.應(yīng)用程序或者運(yùn)行環(huán)境(Runtime)可以對(duì)Pure Function的運(yùn)算結(jié)果進(jìn)行緩存,運(yùn)算加快速度。
        我們繼續(xù)了解函數(shù)式編

  • 函數(shù)式編程

    函數(shù)是第一等公民,能像其它普通變量一樣去,創(chuàng)建,修改,傳遞,我們看可以把block看成函數(shù)

    @interface CalculatorFP : NSObject
    @property (nonatomic, assign) int result;
    - (CalculatorFP *)add:(int(^)(void))block;
    - (CalculatorFP *)sub:(int(^)(void))block;
    - (CalculatorFP *)clean;
    @end
    
    @implementation CalculatorFP
    - (CalculatorFP *)add:(int(^)(void))block {
       int value = block();
       self.result += value;
       return self;
    }
    
    - (CalculatorFP *)sub:(int(^)(void))block {
       int value = block();
       self.result -= value;
       return self;
    }
    
    - (CalculatorFP *)clean {
       self.result = 0;
       return self;
    }
    @end
    
    //sample
    CalculatorFP *fp = [[CalculatorFP alloc] init];
    [[[[fp add:^int{
       return 2;
    }] sub:^int{
       return 1;
    }] clean] add:^int{
       return 3;
    }];
    
    NSLog(@"~~~~ fp value %d",fp.result);
    /*output
     ~~~~ fp value 3
    */
    

    上面的計(jì)算器的例子,已經(jīng)完全夠用。然后我們擴(kuò)展思考一下。假如,我們想表示一個(gè)計(jì)算表達(dá)式如 int c = a + b;并且在a或b值改變的時(shí)候.c能同步改變。怎么做?首先我們要實(shí)現(xiàn)a,b改變的時(shí)候得到通知,所以我們介紹另一個(gè)編程思想,響應(yīng)式編程

  • 響應(yīng)式編程

    直接上代碼

      @interface CalculatorReactive : NSObject
      @property (nonatomic, assign) int value;
      - (void)addObserverValueUpdate:(void(^)(int a))block;
      //這個(gè)方法返回一個(gè)block,調(diào)用該block,就能移除block的監(jiān)聽(tīng)
      - (void(^)(void))addWithRemoveControllerObserverValueUpdate:(void(^)(int))block;
      @end
    
      @interface CalculatorReactive ()
      @property (nonatomic, strong) NSMutableArray<void (^)(int)> *recordObserverUpdateBlockArray;
      @end
    
      @implementation CalculatorReactive
      - (id)init {
          if (self = [super init]) {
              self.recordObserverUpdateBlockArray = [NSMutableArray array];
          }
          return self;
      }
    
      - (void)addObserverValueUpdate:(void(^)(int))block {
          [_recordObserverUpdateBlockArray addObject:block];
      }
    
      - (void(^)(void))addWithRemoveControllerObserverValueUpdate:(void(^)(int))block {
          void(^removeBlock)(void) = ^{
              [_recordObserverUpdateBlockArray removeObject:block];
          };
    
          [_recordObserverUpdateBlockArray addObject:block];
          return removeBlock;
      }
    
      - (void)setValue:(int)value {
          if (_value != value) {
              _value = value;
              [_recordObserverUpdateBlockArray enumerateObjectsUsingBlock:^(void (^ _Nonnull obj)(int), NSUInteger idx, BOOL * _Nonnull stop) {
                  obj(value);
              }];
          }
      }
      @end
    
      //sample
      CalculatorReactive *a = [[CalculatorReactive alloc] init];
      [a addObserverValueUpdate:^(int v) {
          NSLog(@"a new value is %d",v);
      }];
    
      void(^removeBlock)(void) = [a addWithRemoveControllerObserverValueUpdate:^(int v) {
          NSLog(@"a with remove new value %d",v);
      }];
    
      a.value = 10;
      a.value = 5;
      removeBlock();
      a.value = 11;
      /*output
      a new value is 10
      a with remove new value 10
      a new value is 5
      a with remove new value 5
      a new value is 11
      */
    

    OK,為了達(dá)成int c = a + b;完成了第一步,我們能監(jiān)聽(tīng)a,b變化了。為了進(jìn)一步完成目前我們把響應(yīng)式和函數(shù)式結(jié)合一起。

  • 函數(shù)式響應(yīng)式編程

    @interface CalculatorReactiveFP : CalculatorReactive
    - (CalculatorReactiveFP *)addByOther:(CalculatorReactiveFP *)other;
    - (CalculatorReactiveFP *)subByOther:(CalculatorReactiveFP *)other;
    @end
    
    @implementation CalculatorReactiveFP
    - (void)commondDoBlock:(void(^)(void))block other:(CalculatorReactiveFP *)other {
        void(^tmpObserverValueUpdateBlock)(int) = ^(int a) {
            block();
        };
    
        [self.recordObserverUpdateBlockArray addObject:tmpObserverValueUpdateBlock];
        [other.recordObserverUpdateBlockArray addObject:tmpObserverValueUpdateBlock];
    }
    
    - (CalculatorReactiveFP *)addByOther:(CalculatorReactiveFP *)other {
        CalculatorReactiveFP *result = [[CalculatorReactiveFP alloc] init];
    
        [self commondDoBlock:^void{
            int newValue = self.value + other.value;
            result.value = newValue;
        } other:other];
    
        return result;
    }
    
    - (CalculatorReactiveFP *)subByOther:(CalculatorReactiveFP *)other {
        CalculatorReactiveFP *result = [[CalculatorReactiveFP alloc] init];
    
        [self commondDoBlock:^void{
            int newValue = self.value - other.value;
            result.value = newValue;
        } other:other];
    
        return result;
    }
    @end
    
    //sample
    CalculatorReactiveFP *a = [[CalculatorReactiveFP alloc] init];
    [a addObserverValueUpdate:^(int v) {
        NSLog(@"a new value is %d",v);
    }];
    CalculatorReactiveFP *b = [[CalculatorReactiveFP alloc] init];
    [b addObserverValueUpdate:^(int v) {
        NSLog(@"b new value is %d",v);
    }];
    CalculatorReactiveFP *c = [a addByOther:b];
    [c addObserverValueUpdate:^(int v) {
        NSLog(@"c new value is %d",v);
    }];
    
    CalculatorReactiveFP *e = [[c addByOther:a] subByOther:b];
    [e addObserverValueUpdate:^(int v) {
        NSLog(@"e new value is %d",v);
    }];
    
    a.value = 1;
    b.value = 3;
    a.value = 5;
    c.value = 11;
    b.value = 2;
    
    /*output
      a new value is 1
      c new value is 1
      e new value is 2
      b new value is 3
      c new value is 4
      a new value is 5
      c new value is 8
      e new value is 10
      c new value is 11
      e new value is 13
      b new value is 2
      c new value is 7
      e new value is 10
    */
    

    我們基本實(shí)現(xiàn)了int c = b + a;這種運(yùn)用算,用到了函數(shù)式響應(yīng)式編程.ReactiveCocoa也是函數(shù)式響應(yīng)式編程,當(dāng)然我們跟他差很多,但是核心思想是一樣,我們關(guān)注結(jié)果,不關(guān)注具體過(guò)程.這非常重要,請(qǐng)一定記住,響應(yīng)式編程的重點(diǎn)是關(guān)注事務(wù)的關(guān)系.不關(guān)注過(guò)程是怎么樣進(jìn)行的。

    為了更接近ReactiveCocoa,我開(kāi)始進(jìn)一步優(yōu)化,第一步.我們要的不是只支持計(jì)算器,要支持任何數(shù)據(jù)類型,OC中id類型就是泛型.同時(shí)作為管道我們不需要去記錄傳遞過(guò)來(lái)值。接下來(lái),我們離開(kāi)計(jì)算器,我們以Cocoa作為類名前綴.

    //為了方便閱讀,把一些常的block加上別名
    typedef void(^CCSubscribeBlock)(id value);
    typedef void(^CCBlankBlock)(void);
    
    @interface CocoaReactive : NSObject
    //把方法名,由set/observer->send/subscribe
    - (void)sendValue:(id)value;
    - (CCBlankBlock)subscribeValue:(CCSubscribeBlock)block;
    @end
    
    @interface CocoaReactive ()
    @property (nonatomic, strong) NSMutableArray<CCSubscribeBlock> *recordObserverUpdateBlockArray;
    @end
    
    @implementation CocoaReactive
    - (id)init {
        if (self = [super init]) {
            self.recordObserverUpdateBlockArray = [NSMutableArray array];
        }
        return self;
    }
    
    - (void)sendValue:(id)value {
        [_recordObserverUpdateBlockArray enumerateObjectsUsingBlock:^(void (^ _Nonnull obj)(id), NSUInteger idx, BOOL * _Nonnull stop) {
            obj(value);
        }];
    }
    
    - (CCBlankBlock)subscribeValue:(CCSubscribeBlock)block {
        CCBlankBlock removeBlock = ^{
            [_recordObserverUpdateBlockArray removeObject:block];
        };
    
        [_recordObserverUpdateBlockArray addObject:block];
        return removeBlock;
    }
    @end
    
    @interface CocoaReactiveFP : CocoaReactive
    - (CocoaReactiveFP *)processValue:(id(^)(id v))block;
    @end
    @implementation CocoaReactiveFP
    - (CocoaReactiveFP *)processValue:(id(^)(id))block {
        CocoaReactiveFP *result = [[CocoaReactiveFP alloc] init];
        void(^tmpSubscribeBlock)(id) = ^(id a) {
            id newValue = block(a);
            [result sendValue:newValue];
        };
        [self subscribeValue:tmpSubscribeBlock];
        return result;
    }
    @end
    
    //sample
    CocoaReactiveFP *a = [[CocoaReactiveFP alloc] init];
    
    CocoaReactiveFP *b = [[a processValue:^id(id v) {
        int tmpV = [v intValue];
        return @(tmpV + 3);
    }] processValue:^id(id v) {
        int tmpV = [v intValue];
        return @(tmpV + 5);
    }];
    
    [b subscribeValue:^(id v) {
        NSLog(@"b new value %@",v);
    }];
    
    [a sendValue:@(2)];;
    /*output
      b new value 10
    */
    

    上面的例子,可以清楚的看到流程:a收到一個(gè)值,b就會(huì)在這基礎(chǔ)上+3再+5,然后再返回這個(gè)值給b.我們大概實(shí)現(xiàn)了一個(gè)管道作用于另一個(gè)管道。即 b = a + (N個(gè)block);我們能否實(shí)現(xiàn) c = a + b;,a,b同時(shí)是管道呢,當(dāng)然能,我們返回值變成一個(gè)管道試試。我們搞個(gè)分類

    @interface CocoaReactiveFP (optimize)
    - (CocoaReactiveFP *)processValue2:(CocoaReactiveFP *(^)(id v))block;
    @end
    
    @implementation CocoaReactiveFP (optimize)
    - (CocoaReactiveFP *)processValue2:(CocoaReactiveFP *(^)(id v))block {
        CocoaReactiveFP *result = [[CocoaReactiveFP alloc] init];
        void(^tmpSubscribeBlock)(id) = ^(id a) {
            //這里返回了一個(gè)管道,我們訂閱這個(gè)管道,當(dāng)它有值過(guò)來(lái),我們就傳給result
            CocoaReactiveFP *reactive = block(a);
            void(^tmpSubscribeReactiveBlock)(id) = ^(id a) {
                [result sendValue:a];
            };
            [reactive subscribeValue:tmpSubscribeReactiveBlock];
        };
        [self subscribeValue:tmpSubscribeBlock];
        return result;
    }
    @end
    
    //sample
    CocoaReactiveFP *a = [[CocoaReactiveFP alloc] init];
    CocoaReactiveFP *b = [[CocoaReactiveFP alloc] init];
    
    CocoaReactiveFP *c = [a processValue2:^CocoaReactiveFP *(id v) {
        return b;
    }];
    
    [c subscribeValue:^(id v) {
        NSLog(@"c new value %@",v);
    }];
    
    [a sendValue:@(2)];
    [b sendValue:@(20)];
    
    /*output
      c new value 20
    */
    

    我們實(shí)現(xiàn)返回一個(gè)全新的管道.然后訂閱它,它的值傳過(guò)來(lái)后我們傳給我們要的管道。但是這段代碼怎么看都不舒服,它有以下三個(gè)問(wèn)題.

    1. 不夠Lazy,管道b直接就初始化出來(lái)的,我希望,應(yīng)該是[c subscribeValue:...];時(shí)候創(chuàng)建
    2. 管道a的值被無(wú)視了,直接無(wú)用了。
    3. 回顧一下我上面提到的side effects/pure function.processValue2的參數(shù)block,不是prue function。它防問(wèn)了外部變量b,產(chǎn)生了副作用.怎么改呢,可以參考上面的例子,將防問(wèn)外部變量打包到一個(gè)函數(shù)中,然后將這個(gè)函數(shù)作為返回值.這里的函數(shù)即我們的block.我們動(dòng)手改吧,
    
    @class CocoaReactiveFP;
    //方便閱讀我們將方法processValue2 的參數(shù)block加別名
    typedef CocoaReactiveFP *(^CCBindBlock)(id value);
    @interface CalculatorReactiveFP (Lazy)
    - (CocoaReactiveFP *)processValueLazy:(CCBindBlock(^)(void))block;
    @end
    
    @implementation CocoaReactiveFP (Lazy)
    - (CocoaReactiveFP *)processValueLazy:(CCBindBlock(^)(void))block {
        CocoaReactiveFP *result = [[CocoaReactiveFP alloc] init];
        void(^tmpSubscribeBlock)(id) = ^(id a) {
            //block將在有subscribe的時(shí)候才調(diào)用
            CCBindBlock bindBlock = block();
            CocoaReactiveFP *bindReactive = bindBlock(a);
            void(^tmpBindReactiveSubscribeBlock)(id) = ^(id a) {
                [result sendValue:a];
            };
            [bindReactive subscribeValue:tmpBindReactiveSubscribeBlock];
        };
        [self subscribeValue:tmpSubscribeBlock];
        return result;
    }
    @end
    
    //sample
    CocoaReactiveFP *aLazy = [[CocoaReactiveFP alloc] init];
    
    CocoaReactiveFP *cLazy = [aLazy processValueLazy:^CCBindBlock{
        return ^CocoaReactiveFP *(id v){
            CocoaReactiveFP *bLazy = [[CocoaReactiveFP alloc]init];
            //尷尬的我們發(fā)現(xiàn)bLazy,無(wú)處sendValue.在這sendValue的話,
            //cLazy還未subscribe bLazy.
            return bLazy;
        };
    }];
    
    [cLazy subscribeValue:^(id value) {
        NSLog(@"cLazy new value %@",value);
    }];
    
    [aLazy sendValue:@(2)];
    [aLazy sendValue:@(5)];
    

    看到上面好尷尬,我們無(wú)法對(duì)bLazy調(diào)用sendValue,想了想,我們需要給bLazy開(kāi)個(gè)block,當(dāng)有人訂閱它的時(shí)候,通知我們,我們就可以在那個(gè)block里面sendValue,馬上動(dòng)手

    @interface CocoaReactiveFP (Lazy2)
    - (CocoaReactiveFP *)createReactiveFPLazy:(void(^)(CCSubscribeBlock o))block;
    @end
    
    @interface CocoaReactiveFP ()
    //
    @property (nonatomic, copy) void (^createBlock)(CCSubscribeBlock o);
    @end
    
    @implementation CocoaReactiveFP (Lazy2)
    - (CocoaReactiveFP *)createReactiveFPLazy:(void(^)(CCSubscribeBlock o))block {
        CocoaReactiveFP *lazy = [[CocoaReactiveFP alloc] init];
        lazy.createBlock = block;
        return lazy;
    }
    
    - (CCBlankBlock)subscribeValue:(CCSubscribeBlock)block {
        CCBlankBlock result = [super subscribeValue:block];
        //當(dāng)有人subscribe的時(shí)候我們就調(diào)用_createBlock通知外界
        if (_createBlock) {
            _createBlock(block);
        }
        return result;
    }
    @end
    
    //sample
    CocoaReactiveFP *aLazy = [[CocoaReactiveFP alloc] init];
    
    CocoaReactiveFP *cLazy = [aLazy processValueLazy:^CCBindBlock{
        return ^CocoaReactiveFP *(id v){
            CocoaReactiveFP *bLazy = [CocoaReactiveFP createReactiveFPLazy:^(CCSubscribeBlock o) {
                o(@([v intValue] + 5));
            }];
            return bLazy;
        };
    }];
    
    [cLazy subscribeValue:^(id value) {
        NSLog(@"cLazy new value %@",value);
    }];
    
    [aLazy sendValue:@(2)];
    [aLazy sendValue:@(5)];
    /*output
      cLazy new value 7
      cLazy new value 10
    */
    

    很好,這么寫解決了上面三個(gè)問(wèn)題,bLazy,是lazy create.processValueLazy的參數(shù)block沒(méi)有副作用,是純函數(shù).a管道的值也得到利用了.總體來(lái)說(shuō),還算不錯(cuò).我們還有最后一步

    我們重新思考一下函數(shù)式響應(yīng)式編程.首先它由兩種編程風(fēng)格結(jié)合在一起,在OC單繼承語(yǔ)種上,他們是有先后的,我們上面的例子,是吶應(yīng)式在前,函數(shù)式在后.在ReactiveCocoa中,是相反的,函數(shù)式在前,響應(yīng)式在后.萬(wàn)物皆是流,我們改一下.同時(shí)有些微調(diào)。

    @interface CocoaSubscriber : NSObject
    + (instancetype)subscriberWithValueBlock:(CCSubscribeBlock)block;
    - (void)sendValue:(id)value;
    @end
    
    @class CocoaStream;
    typedef CocoaStream *(^CCStreamBindBlock)(id value);
    @interface CocoaStream : NSObject
    - (__kindof CocoaStream *)bind:(CCStreamBindBlock(^)(void))block;
    @end
    
    @interface CocoaSignal : CocoaStream
    - (CocoaSignal *)createSignal:(void(^)(CocoaSubscriber *subscriber))createBlock;
    - (CCBlankBlock)subscribeValue:(CCSubscribeBlock)block;
    @end
    
    @interface CocoaSubscriber ()
    @property (nonatomic, copy) CCSubscribeBlock valueBlock;
    @property (nonatomic, readonly) CCBlankBlock dispose;
    @end
    
    @implementation CocoaSubscriber
    - (instancetype)subscriberWithValueBlock:(CCSubscribeBlock)block {
        CocoaSubscriber *result  = [[CocoaSubscriber alloc] init];
        result.valueBlock = block;
        return result;
    }
    
    - (id)init {
        if (self = [super init]) {
            __weak CocoaSubscriber *wself = self;
            _dispose = ^{
                __weak CCSubscribeBlock wblock = wself.valueBlock;
                if (wblock) {
                    wblock = NULL;
                }
            };
        }
        return self;
    }
    
    - (void)sendValue:(id)value {
        if (_valueBlock) {
            _valueBlock(value);
        }
    }
    @end
    
    @implementation CocoaStream
    - (__kindof CocoaStream *)bind:(CCStreamBindBlock(^)(void))block {
        NSString *reason = [NSString stringWithFormat:@"%@ must be overridden by subclasses", NSStringFromSelector(_cmd)];
        @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:reason userInfo:nil];
    }
    @end
    
    @interface CocoaSignal ()
    @property (nonatomic, copy) void(^createBlock)(CocoaSubscriber *o);
    @end
    
    @implementation CocoaSignal
    - (CocoaSignal *)createSignal:(void(^)(CocoaSubscriber *subscriber))createBlock; {
        CocoaSignal *signal = [[CocoaSignal alloc] init];
        signal.createBlock = createBlock;
        return signal;
    }
    
    - (CCBlankBlock)subscribeValue:(CCSubscribeBlock)block {
        CocoaSubscriber *subscriber = [CocoaSubscriber subscriberWithValueBlock:block];
        if (_createBlock) {
            _createBlock(subscriber);
        }
        return subscriber.dispose;
    }
    
    - (CocoaSignal *)bind:(CCStreamBindBlock(^)(void))block {
        return [CocoaSignal createSignal:^(CocoaSubscriber *subscriber) {
            CCStreamBindBlock bindBlock = block();
            void(^tmpSubscribeBlock)(id) = ^(id a) {
                CocoaSignal *bindReactive = (CocoaSignal *)bindBlock(a);
                void(^tmpBindReactiveSubscribeBlock)(id) = ^(id a) {
                    [subscriber sendValue:a];
                };
                [bindReactive subscribeValue:tmpBindReactiveSubscribeBlock];
            };
            [self subscribeValue:tmpSubscribeBlock];
        }];
    }
    @end
    
    //sample
    CocoaSignal *aSignal = [CocoaSignal createSignal:^(CocoaSubscriber *subscriber) {
        [subscriber sendValue:@(2)];
        [subscriber sendValue:@(5)];
    }];
    
    CocoaSignal *cSignal = [aSignal bind:^CCStreamBindBlock{
        return ^CocoaSignal *(id v){
            CocoaSignal *bSignal = [CocoaSignal createSignal:^(CocoaSubscriber *subscriber) {
                int newValue =  [v intValue] + 5;
                [subscriber sendValue:@(newValue)];
            }];
            return bSignal;
        };
    }];
    
    [cSignal subscribeValue:^(id value) {
        NSLog(@"cSignal new value %@",value);
    }];
    /*output
      cSignal new value 7
      cSignal new value 10
    */
    

    沒(méi)錯(cuò),這是微調(diào),我感覺(jué)有點(diǎn)ReactiveCocoa的模樣了,你們覺(jué)得呢?

  • 總結(jié)

    如果通遍下來(lái)要做個(gè)總結(jié)的話,我覺(jué)得的最最最重要的是,思想的轉(zhuǎn)變.RAC是構(gòu)建事務(wù)關(guān)系的工具,不要用命令式那種關(guān)注過(guò)程的思想去思考它。

  • demo
    github

  • 題外話

    這個(gè)是ReactiveCocoa分享的第一節(jié),很多細(xì)節(jié)解釋在分享上講。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容