信號(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ā)送到需要的地方。

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ù)雜場景下的使用流程介紹給大家。
希望能對您有一點幫助。