ReactiveCocoa源码拆分解析(四)
(整個關于ReactiveCocoa的代碼工程可以在https://github.com/qianhongqiang/QHQReactive下載)
上一章節簡要的說明了如何實現的熱信號。但是像那么寫,貌似不是非常優雅。這一章節我們會把冷熱信號轉換寫的跟ReactiveCocoa一樣優雅。
ReactiveCocoa內部是如何實現冷熱信號轉換的呢?我們來看個例子
? ?RACSignal *replayLazilySignal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
?? ? ? NSLog(@"replaylazily---sendAction");
? ? ? ? [subscriber sendNext:@"replaylazily"];
? ? ? ? return nil;
? ? }] replayLazily];
?? ?
? ? [replayLazilySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"subscribe1----%@",x);
? ? }];
?? ?
? ? [replayLazilySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"subscribe2----%@",x);
? ? }];
沒錯,只是在原有信號的基礎上,增加了一個replayLazily方法掉用。我們從輸出上可以看看,是否轉為了熱信號。
2015-12-29 13:28:03.588 xxxxxx[40933:6054173] <xxxxxx:(232)> replaylazily---sendAction
2015-12-29 13:28:03.589 xxxxxx[40933:6054173] <xxxxxx:(238)> subscribe1----replaylazily
2015-12-29 13:28:03.589 xxxxxx[40933:6054173] <xxxxxx:(242)> subscribe2----replaylazily
發送只有1次,被訂閱了兩次。那么我們也朝這個目標出發。
我們這次讓一個熱信號QHQSubject去訂閱最初的冷信號,偷偷的將返回改成這個熱信號,偷梁換柱而神不知鬼不覺。
-(QHQSignal *)replayLazily {
? ? QHQMulticastConnection *conn = [[QHQMulticastConnection alloc] initWithSourceSignal:self outSignalSubject:[[QHQSubject alloc] init]];
? ? [conn connectSignal];
? ? return conn.connSignal;
}
這里用到了一個新類,用于做這層轉化QHQMulticastConnection,它需要一個源,和一個訂閱信號。當執行connectSignal方法后,讓熱信號訂閱最初信號。
-(void)connectSignal {
? ? [_sourceSignal subscribe:_connSignal];
}
讓熱信號稱為接下來流的來源??此埔呀浱煲聼o縫了,執行下,看看結果如何
-(void)demoFourReplayLazily {
? ? QHQSignal *replaySignal = [[QHQSignal createSignal:^(id subscriber) {
? ? ? ? [subscriber sendNext:@"replaySignal---send"];
? ? }] replayLazily];
?? ?
? ? [replaySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"sub1 ---- %@",x);
? ? }];
?? ?
? ? [replaySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"sub2 ---- %@",x);
? ? }];
}
2015-12-29 13:39:59.345 PageText[42204:6070078] replaySignal----send
怎么沒有輸出訂閱的結果呢?確實不應該輸出結果,開始分析下原因。當你掉用replayLazily方法時,你已經偷偷摸摸將信號換成了QHQSubject,在這個過程中,你已經訂閱了信號,也就是最終的輸出結果。讓后你再去訂閱這個QHQSubject的時候,它做不了任何事情,因為信號的發送已經過去了,過去了,了。我們可以做個延遲發送事件看看。
? ??QHQSignal *replaySignal = [[QHQSignal createSignal:^(id subscriber) {
? ? ? ? NSLog(@"replaySignal----send");
? ? ? ? [subscriber sendNext:@"replaySignal---send"];
?? ? ? ?
? ? ? ? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
? ? ? ? ? ? NSLog(@"Delay-----replaySignal----send");
? ? ? ? ? ? [subscriber sendNext:@"Delay-----replaySignal---send"];
? ? ? ? });
?? ? ? ?
? ? }] replayLazily];
?? ?
? ? [replaySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"sub1 ---- %@",x);
? ? }];
?? ?
? ? [replaySignal subscribeNext:^(id x) {
? ? ? ? NSLog(@"sub2 ---- %@",x);
? ? }];
發送了兩次事件,一次是理解發送,另一次做了延遲??纯唇Y果
2015-12-29 13:45:35.560 PageText[42399:6074028] replaySignal----send
2015-12-29 13:45:37.561 PageText[42399:6074028] Delay-----replaySignal----send
2015-12-29 13:45:37.562 PageText[42399:6074028] sub1 ---- Delay-----replaySignal---send
2015-12-29 13:45:37.562 PageText[42399:6074028] sub2 ---- Delay-----replaySignal---send
延遲發送的事件確實收到了,說明確實轉化成了熱信號。但是我們總不能每次都延遲一下吧,當然我們可以搞定這個問題,我們讓熱信號把事件存起來,訂閱這訂閱后把事件都發送出去。這個時候需要一個可以保存事件的熱信號。
因此,我們創建了一個新類繼承于QHQSubject
@interface QHQReplaySubject ()
@property (nonatomic, assign) NSUInteger capacity;
@property (nonatomic, strong) NSMutableArray *values;
@end
它會將每次發送來的事件保存在values數組中,如果數組容量大于承載capacity,將會移除掉更早的事件
-(void)sendNext:(id)next {
? ? [_values addObject:next];
? ? [super sendNext:next];
?? ?
? ? if (_values.count >_capacity) {
? ? ? ? [_values removeObjectAtIndex:0];
? ? }
}
它每次被訂閱時,都需要首先將已經保存的信號發送給訂閱著
-(void)subscribe:(id<QHQSubscrib>)sub {
? ? for (id value in _values) {
? ? ? ? [sub sendNext:value];
? ? }
? ? [self.subscribers addObject:sub];
}
這樣,第一次的信號就不會丟失。
-(QHQSignal *)replayLazily {
? ? QHQMulticastConnection *conn = [[QHQMulticastConnection alloc] initWithSourceSignal:self outSignalSubject:[QHQReplaySubject replaySubjectWithCapacity:1]];
? ? [conn connectSignal];
? ? return conn.connSignal;
}
簡單的將熱信號替換成能夠保存1個老信號的熱信號,那么問題迎刃而解
2015-12-29 14:02:00.766 PageText[43381:6084580] replaySignal----send
2015-12-29 14:02:00.767 PageText[43381:6084580] sub1 ---- replaySignal---send
2015-12-29 14:02:00.767 PageText[43381:6084580] sub2 ---- replaySignal---send
2015-12-29 14:02:02.768 PageText[43381:6084580] Delay-----replaySignal----send
2015-12-29 14:02:02.769 PageText[43381:6084580] sub1 ---- Delay-----replaySignal---send
2015-12-29 14:02:02.770 PageText[43381:6084580] sub2 ---- Delay-----replaySignal---send
?
輸出符合預期
實際上,RAC也是這么做的,不過它將所有的接口都處理成線程安全的。
轉載于:https://www.cnblogs.com/qianhongqiang/p/5085556.html
總結
以上是生活随笔為你收集整理的ReactiveCocoa源码拆分解析(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到大黑狗进家是怎么回事
- 下一篇: 一个简单的optimizer_trace