你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS技巧綜合 >> ReactiveCocoa比較區分replay, replayLast和replayLazily

ReactiveCocoa比較區分replay, replayLast和replayLazily

編輯:IOS技巧綜合
[摘要]本文是對ReactiveCocoa比較區分replay, replayLast和replayLazily的講解,對學習IOS蘋果軟件開發有所幫助,與大家分享。

一直搞不明白replayLazily可以直接跳到最後看。

 原文:http://spin.atomicobject.com/2014/06/29/replay-replaylast-replaylazily/

  最近同事問我在ReactiveCoca中replay,replayLast和replayLazily有什麼區別,但我對此也是一知半解,也不能完整描述出來它們之間的不同,所以,我將對它們進行深入研究。

  如果你沒有對RACReplaySubject和RACMulticastConnection有很好的理解的話,你會對它們在頭文件中的描述理解的很困難。現在不去了解底層原理,我會嘗試去描述解析這些方法。

Subscribing to a Signal

  對於一個“普通”的信號,每次訂閱都將會導致信號中的代碼再執行一遍,且該次訂閱者僅接收到該次訂閱發送出去的值。

  第一個例子演示每次訂閱都會重新執行訂閱代碼。

__block int num = 0;
  RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id  subscriber) {
      num++;
      NSLog(@"Increment num to: %i", num);
      [subscriber sendNext:@(num)];
      return nil;
  }];
 
  NSLog(@"Start subscriptions");
 
  // Subscriber 1 (S1)
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  // Subscriber 2 (S2)
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  // Subscriber 3 (S3)
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];

  運行結果如下:

Start subscriptions
  Increment num to: 1
  S1: 1
  Increment num to: 2
  S2: 2
  Increment num to: 3
  S3: 3

  可以看到,每次訂閱num都在遞增,如果不訂閱則不會遞增。通過這種方式,可以知道信號是懶惰的,如果沒有訂閱者的話,是不會執行的。

  第二個例子演示信號被添加訂閱的時候,訂閱者是怎麼接收發送的值的。

 RACSubject *letters = [RACSubject subject];
  RACSignal *signal = letters;
 
  NSLog(@"Subscribe S1");
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  NSLog(@"Send A");
  [letters sendNext:@"A"];
  NSLog(@"Send B");
  [letters sendNext:@"B"];
 
  NSLog(@"Subscribe S2"); 
  [signal subscribeNext:^(id x) { 
      NSLog(@"S2: %@", x);
  }];
 
  NSLog(@"Send C");
  [letters sendNext:@"C"];
  NSLog(@"Send D");
  [letters sendNext:@"D"];
 
  NSLog(@"Subscribe S3");
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];

運行結果

Subscribe S1
 
Send A
S1: A
 
Send B
S1: B
 
Subscribe S2
 
Send C
S1: C
S2: C
 
Send D
S1: D
S2: D
 
Subscribe S3

  在很多情況下,這是我們想要的預期結果,不過在某些情況下,你不需要訂閱的代碼再次被執行。例如訂閱 一個向網絡服務器發送的請求,當服務器返回數據時,多個監聽者需要更新(無論有多少個監聽者,請求只發送一下(第一個例子就不滿足我們的需求)),或者我們想拿到訂閱前信號發送過的值(第二個例子,S2想拿A,B的值或者S3想拿A,B,C,D的值,就不滿足我們的需求了)。因此-replay,-replayLast, and-replayLazily應需而生。

Subscribing to a -replay Signal

  這個replay方法將返回一個新的信號,當源信號被訂閱時,會立即發送給訂閱者全部歷史的值,不會重復執行源信號中的訂閱代碼,不僅如此,訂閱者還將收到所有未來發送過去的值。

  第一個例子演示信號添加新的訂閱時,代碼是不會再次被執行的。

__block int num = 0;
  RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id  subscriber) {
      num++;
      NSLog(@"Increment num to: %i", num);
      [subscriber sendNext:@(num)];
      return nil;
  }] replay];
 
  NSLog(@"Start subscriptions");
 
  // Subscriber 1 (S1)
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  // Subscriber 2 (S2)
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  // Subscriber 3 (S3)
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
Increment num to: 1
  Start subscriptions
  S1: 1
  S2: 1
  S3: 1

  信號首次被訂閱時,num立馬被遞增了,且僅僅遞增了一次。這說明了不管有你多個訂閱者,訂閱代碼我只執行了一次。

  

  第二個例子演示每個新添加的訂閱者接收到信號中全部的值(不管是之前發出的值還是將來發出的值)。

  

RACSubject *letters = [RACSubject subject];
  RACSignal *signal = [letters replay];
 
  NSLog(@"Subscribe S1");
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  NSLog(@"Send A");
  [letters sendNext:@"A"];
  NSLog(@"Send B");
  [letters sendNext:@"B"];
 
  NSLog(@"Subscribe S2");
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  NSLog(@"Send C");
  [letters sendNext:@"C"];
  NSLog(@"Send D");
  [letters sendNext:@"D"];
 
  NSLog(@"Subscribe S3");
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
Subscribe S1   
 
Send A   
S1: A
 
Send B
S1: B
 
Subscribe S2
S2: A
S2: B
 
Send C
S1: C
S2: C
 
Send D
S1: D
S2: D
 
Subscribe S3
S3: A
S3: B
S3: C
S3: D

  盡管訂閱者S3在所有的值發送之後再訂閱,然後還能接收到所有的值。

Subscribing to a -replayLast Signal

  這個replayLast返回一個新的信號,當源信號被訂閱時,會立即發送給訂閱者最新的值,不會重復執行源信號中的訂閱代碼。訂閱者還會收到信號未來所有的值。

  對於第一個例子,跟之前replay一樣,所以我就不再次演示了。

  第二個例子演示如何將最新的值提供給新的訂閱者

RACSubject *letters = [RACSubject subject];
  RACSignal *signal = [letters replayLast];
 
  NSLog(@"Subscribe S1");
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  NSLog(@"Send A");
  [letters sendNext:@"A"];
  NSLog(@"Send B");
  [letters sendNext:@"B"];
 
  NSLog(@"Subscribe S2");
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  NSLog(@"Send C");
  [letters sendNext:@"C"];
  NSLog(@"Send D");
  [letters sendNext:@"D"];
 
  NSLog(@"Subscribe S3");
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
Subscribe S1
 
Send A
S1: A
 
Send B
S1: B
 
Subscribe S2
S2: B
 
Send C
S1: C
S2: C
 
Send D
S1: D
S2: D
 
Subscribe S3
S3: D

Subscribing to a -replayLazily Signal

  這replayLazily方法返回一個新的信號,當源信號被訂閱時,會立即發送給訂閱者全部歷史的值,不會重復執行源信號中的訂閱代碼。跟replay不同的是,replayLazily被訂閱生成新的信號之前是不會對源信號進行訂閱的(原文寫的有點繞,簡單來講 直到訂閱時候才真正創建一個信號,源信號的訂閱代碼才開始執行)。暫時不理解也沒事,看下面的代碼輸出,和注釋。

 這第一個例子會說明跟replay差異。 注意字符串“Increment num to: 1”是被訂閱了之後才打印顯示的。而replay和replayLast沒被訂閱前就打印了“Increment num to: 1” 這個消息。

__block int num = 0;
  RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id  subscriber) {
      num++;
      NSLog(@"Increment num to: %i", num);
      [subscriber sendNext:@(num)];
      return nil;
  }] replayLazily];  //跟replay不同的就這麼一個地方
 
  NSLog(@"Start subscriptions");
 
  // Subscriber 1 (S1)
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  // Subscriber 2 (S2)
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  // Subscriber 3 (S3)
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
// 帖子滾動起來,跟replay比較一下 Increment num to: 1 的顯示順序。

Start subscriptions     // 實際訂閱
Increment num to: 1 // 信號開始創建
S1: 1
S2: 1
S3: 1

  第二個例子演示將全部歷史的值提供給任何新的訂閱者,就像replay一樣。

RACSubject *letters = [RACSubject subject];
  RACSignal *signal = [letters replayLazily];
 
  NSLog(@"Subscribe S1");
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  NSLog(@"Send A");
  [letters sendNext:@"A"];
  NSLog(@"Send B");
  [letters sendNext:@"B"];
 
  NSLog(@"Subscribe S2");
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  NSLog(@"Send C");
  [letters sendNext:@"C"];
  NSLog(@"Send D");
  [letters sendNext:@"D"];
 
  NSLog(@"Subscribe S3");
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
Subscribe S1
 
Send A
S1: A
 
Send B
S1: B
 
Subscribe S2
S2: A
S2: B
 
Send C
S1: C
S2: C
 
Send D
S1: D
S2: D
 
Subscribe S3
S3: A
S3: B
S3: C
S3: D

  總結一下:

  ReactiveCocoa提供了這三個簡便的方法允許多個訂閱者訂閱一個信號,卻不會重復執行訂閱代碼,並且能給新加的訂閱者提供訂閱前的值。replay和replayLast使信號變成熱信號,且會提供所有值(-replay) 或者最新的值(-replayLast) 給訂閱者。replayLazily返回一個冷的信號,會提供所有的值給訂閱者。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved