ReactiveCocoa解讀-訂閱信號

信號(Signal)和訂閱者(Subscriber)是在ReactiveCocoa( 下文簡稱RAC)的相關(guān)資料中提到最多的概念了,但因為是從英文語境中直接翻譯過來的,讓國內(nèi)大部分開發(fā)者對訂閱信號一時難以理解,即使掌握了RAC的用法對此還是模棱兩可。今天,我們嘗試從RAC的源碼去解讀,看看訂閱信號到底是個啥子過程。

先上一段RAC最簡單的使用方法。

 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"鋼鐵鍋"];
    [subscriber sendNext:@"含眼淚喊修瓢鍋"];
    [subscriber sendNext:@"壞缺爛角的換新鍋瓢亂放"];
    [subscriber sendNext:@"哎...哎,哎,誰的鞋,不要亂扔..."];
    return [RACDisposable disposableWithBlock:^{
        NSLog(@"曲終人散,抹點藥酒");
    }];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"我聽到:%@",x);
}];
這是什么鍋

信號是信息的載體

對應(yīng)上邊的代碼,我們創(chuàng)建了一個信號 signal,他承載著 鋼鐵鍋 含眼淚喊修瓢鍋 壞缺爛角的換新鍋瓢亂放 哎...哎,哎,誰的鞋,不要亂扔...這些信息。

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}

創(chuàng)建信號很簡單,其實就是創(chuàng)建了一個實例對象,并把將來有可能進行的一系列操作didSubscribe這個block記錄下來,等發(fā)生了訂閱行為時就會執(zhí)行這些操作。
有人會問RACDisposable是什么東西,其實從字面就可以理解,銷毀,它封裝了當訂閱行為消失時一些應(yīng)該做的操作,當然像一開始的代碼這種只是打印消息的操作其實是沒必要的,所以這里可以返回nil。那什么時候訂閱行為消失呢,當訂閱者調(diào)用了sendError:或者sendCompleted方法時表示訂閱行為就消失了,相應(yīng)的dispose就會執(zhí)行了,做一些清理操作。如下面的代碼:

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"鋼鐵鍋"];
    [subscriber sendNext:@"含眼淚喊修瓢鍋"];
    [subscriber sendError:[NSError errorWithDomain:@"singing" code:748 userInfo:@{@"reason":@"麥克被歌迷拔掉了"}]];
    [subscriber sendNext:@"壞缺爛角的換新鍋瓢亂放"];
    [subscriber sendNext:@"哎...哎,哎,誰的鞋,不要亂扔..."];
    [subscriber sendError:NULL];
//        [subscriber sendCompleted];
    return [RACDisposable disposableWithBlock:^{
        NSLog(@"曲終人散,抹點藥酒");
    }];
}];
我錯了

當然如果這兩個方法如果你都不調(diào)用,那么當訂閱者超出了自己的生命周期調(diào)用其dealloc方法時這個dispose也會執(zhí)行。所以RACDisposable在RAC里使用非常廣泛,比如在NSNotificationCenter的RAC擴展中用于取消觀察者,在UITextField和UITextView的擴展里取消代理等等。

說了半天大家可能會問,訂閱者在哪里?別急,看下面:

[signal subscribeNext:^(id x) {
    NSLog(@"我聽到:%@",x);
}];

當這句代碼執(zhí)行時就發(fā)生了訂閱行為。其內(nèi)部實現(xiàn)是這樣:

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
     NSCParameterAssert(nextBlock != NULL);
     //看到了嗎?我在這里,我就是訂閱者。我把 nextBlock保存了下來。
     RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock   error:NULL completed:NULL];
     return [self subscribe:o];
}

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
     NSCParameterAssert(subscriber != nil);
     RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
     //加工了一下,變成了RACPassthroughSubscriber,關(guān)于它的作用我們在以后的文章總具體場景下再講述,現(xiàn)在你只需記住一個更具體的RACSubscriber子類就行了。
     subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
     //還記得信號在一開始創(chuàng)建時就存下來的那個block嗎,就是這個didSubscribe
     if (self.didSubscribe != NULL) {
         RACDisposable *schedulingDisposable =  [RACScheduler.subscriptionScheduler schedule:^{
             //在這里支行了信號一開始創(chuàng)建的block,并獲得了它返回的RACDisposable
             RACDisposable *innerDisposable = self.didSubscribe(subscriber);
             [disposable addDisposable:innerDisposable];
         }];
        [disposable addDisposable:schedulingDisposable];
    }
    return disposable;
}

看到這里你可能有產(chǎn)生了很多疑問,且聽我慢慢道來。首先你在頭腦里先產(chǎn)生這個場景:生成了一個subscriber(代號007),它保存了一個nextBlock:^(id x) { NSLog(@"我聽到:%@",x);},然后當前這個信號開始執(zhí)行didSubscribe這個block:

^RACDisposable *(id<RACSubscriber> subscriber) { 
  [subscriber sendNext:@"鋼鐵鍋"];
  [subscriber sendNext:@"含眼淚喊修瓢鍋"];
  [subscriber sendNext:@"壞缺爛角的換新鍋瓢亂放"]; 
  [subscriber sendNext:@"哎...哎,哎,誰的鞋,不要亂扔..."];
  [subscriber sendCompleted]; 
  return [RACDisposable disposableWithBlock:^{
       NSLog(@"曲終人散,抹點藥酒"); 
  }];
}

注意,007被當作參數(shù)傳了進去,也就是調(diào)用sendNext:這個方法的都是007,還記得007保存的那個nextBlock嗎,此時在sendNext:內(nèi)部就是執(zhí)行了這個nextBlock,傳進去了鋼鐵鍋 含眼淚喊修瓢鍋 壞缺爛角的換新鍋瓢亂放 哎...哎,哎,誰的鞋,不要亂扔...這些信息。這樣作為開發(fā)者的你就收到了訂閱者發(fā)給你的有用信息,你就“聽”到了一首美妙的歌曲。

整個一個訂閱流程就這樣結(jié)束了,當然你會發(fā)現(xiàn)在你的代碼中subscriber始終都沒暴露出來,這也是造成你疑惑的原因,那么我問你,你需要的是subscriber呢,還是subscriber發(fā)給你的信息呢?因為我們需要的只是信息,所以完全沒必要讓我們知道subscriber的存在。所謂的訂閱者也就是subscriber其實就是起了一個中間人的作用,獲取信號(或者叫信號源更好理解)里的信息,然后發(fā)送到需要的地方。

keynote圖形好少啊

RACCompoundDisposable(RACDisposable的子類)應(yīng)該是大家的另一個疑問,它有一個方法addDisposable:可以添加另一個RACDisposable,它的最終形態(tài)是一個樹形結(jié)構(gòu),第一個RACCompoundDisposable存了若干個RACDisposable或者RACCompoundDisposable,相應(yīng)的RACCompoundDisposable又存了若干個RACDisposable或者RACCompoundDisposable...每個元素里邊存的都是一些block形式存在的清理操作,這樣當執(zhí)行樹的根節(jié)點的dispose時,整棵樹就會按順序執(zhí)行清理操作了。

那么,講到這里就先告一段落了,等有時間我會把RAC更復(fù)雜場景下的使用流程介紹給大家。

希望能對您有一點幫助。

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

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

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