簡(jiǎn)介
ReactiveCocoa 是一個(gè)重型的 FRP (Functional Reactive Programming 是一種響應(yīng)變化的編程范式) 框架。內(nèi)部使用了大量的block。FRP的核心就是信號(hào)。
RACSignal就是信號(hào),是ReactiveCocoa中很重要的一個(gè)概念。RACSignal本體是RACStream。信號(hào)就是數(shù)據(jù)流,可以用來傳遞和綁定。
以下代碼基于V2.5的ReactiveCocoa
創(chuàng)建RACsignal
不說廢話,先來一張圖
// 源碼
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
通過RACDynamicSignal
創(chuàng)建信號(hào),此時(shí)傳入一個(gè)block,這個(gè)block的參數(shù)是一個(gè)遵循RACSubscriber
協(xié)議的一個(gè)變量,同時(shí)這個(gè)block的返回值是一個(gè)RACDisposable
類型。
通過源碼分析,看到RACDynamicSignal
有一個(gè)屬性didSubscribe
存儲(chǔ)了傳進(jìn)來的的block,這個(gè)屬性將在之后訂閱的時(shí)候使用。
這個(gè)RACSubscriber的協(xié)議,其中定義了幾個(gè)方法
@protocol RACSubscriber <NSObject>
@required
// 發(fā)送next需要執(zhí)行的參數(shù)
- (void)sendNext:(id)value;
// 發(fā)送錯(cuò)誤
- (void)sendError:(NSError *)error;
// 發(fā)送成功
- (void)sendCompleted;
// 處理信號(hào),是否釋放取消訂閱。
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end
創(chuàng)建一個(gè)信號(hào)
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
}];
}];
訂閱
一個(gè)信號(hào)通過調(diào)用subscribeNext
創(chuàng)建一個(gè)subscriber進(jìn)行subscription。
// RACSignal (Subscription) RACSignal.m
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
// 當(dāng)前self是RACDynamicSignal所以,使用RACDynamicSignal.m中的subscribe:方法。
// RACDynamicSignal.m
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}
源碼中創(chuàng)建了一個(gè)RACSubscriber來存儲(chǔ)nextBlock、error、completed。然后訂閱處理subscription。
這里有一個(gè)
RACCompoundDisposable
,這是一個(gè)RACDisposable
,只不過RACCompoundDisposable
可以存放多個(gè)RACDisposable
。當(dāng)RACCompoundDisposable 執(zhí)行dispose方法時(shí),它所存放的disposable都會(huì)被釋放。使用
RACPassthroughSubscriber
將當(dāng)前的訂閱者進(jìn)行轉(zhuǎn)化,轉(zhuǎn)化為另外一種形式的訂閱者。這個(gè)訂閱者中存儲(chǔ)了當(dāng)前的訂閱者,信號(hào)、disposable。存儲(chǔ)了一個(gè)信號(hào)的完整處理,并且這個(gè)訂閱者同樣遵循<RACSubscriber>協(xié)議。這里可以把RACPassthroughSubscriber當(dāng)成是訂閱者的裝飾器(偽裝器)。-
使用RACPassthroughSubscriber的目的是將subscirber傳遞給另一個(gè)還沒有disposed的subscriber。
Passes through all events to another subscriber while not disposed.
-
當(dāng)執(zhí)行self.didSubscribe(subscriber)時(shí)siganle存儲(chǔ)的block就會(huì)被執(zhí)行。當(dāng)sendNext:執(zhí)行時(shí),先執(zhí)行[RACPassthroughSubscriber sendNext:],然后調(diào)用RACPassthroughSubscriber中的subscriber來執(zhí)行
sendNext:
。// 源碼 // 源碼 - (void)sendNext:(id)value { if (self.disposable.disposed) return; if (RACSIGNAL_NEXT_ENABLED()) { RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description])); } [self.innerSubscriber sendNext:value];
}
繼續(xù)執(zhí)行
addDisposable,此時(shí)會(huì)將
RACCompoundDisposable```釋放。
```objc
// 源碼
- (void)addDisposable:(RACDisposable *)disposable {
NSCParameterAssert(disposable != self);
if (disposable == nil || disposable.disposed) return;
BOOL shouldDispose = NO;
OSSpinLockLock(&_spinLock);
{
if (_disposed) {
shouldDispose = YES;
} else {
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
if (_inlineDisposables[i] == nil) {
_inlineDisposables[i] = disposable;
goto foundSlot;
}
}
#endif
if (_disposables == NULL) _disposables = RACCreateDisposablesArray();
CFArrayAppendValue(_disposables, (__bridge void *)disposable);
if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
}
#if RACCompoundDisposableInlineCount
foundSlot:;
#endif
}
}
OSSpinLockUnlock(&_spinLock);
// Performed outside of the lock in case the compound disposable is used
// recursively.
// 會(huì)在此處釋放。
if (shouldDispose) [disposable dispose];
}
6. 源碼中可以看出,訂閱一個(gè)信號(hào),返回的是一個(gè)RACDisposable,作為一個(gè)返回值返回到外部,我們可以在外部對(duì)其取消這個(gè)訂閱。
###總結(jié)
```objc
// part 1.
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 此處subscriber為轉(zhuǎn)換后的subscriber
// part 5.
[subscriber sendNext:@"abc"];
[subscriber sendCompleted];
// part 6.
return [RACDisposable disposableWithBlock:^{
NSLog(@"disposable");
}];
}];
// part 2.
RACDisposable *adisposable = [aSignal subscribeNext:^(id x) {
NSLog(@"~~~~~~~~~~~ %@",x);
}];
- 調(diào)用createSignal:創(chuàng)建一個(gè)信號(hào)。存儲(chǔ)當(dāng)前的block到didSubscribe這個(gè)block中。
- 調(diào)用subscribeNext:訂閱信號(hào)。創(chuàng)建一個(gè)subscriber來subscription。在subscriber中存儲(chǔ)nextBlock,errorBlock,completeBlock三個(gè)block。
- 當(dāng)前的訂閱通過轉(zhuǎn)換,成為RACPassthroughSubscriber,這個(gè)subscriber中有三個(gè)重要的屬性分別是當(dāng)前訂閱的subscriber,當(dāng)前的signal和RACCompoundDisposable。
- RACDynamicSignal執(zhí)行
didSubscribe(RACPassthroughSubscriber)
這個(gè)block。執(zhí)行RACPassthroughSubscriber中的sendNext:, sendError:, sendCompeleted
。 - RACPassthroughSubscriber中通過判斷當(dāng)前的disposable的狀態(tài)來判斷是否告訴subscriber調(diào)用相應(yīng)的
sendNext:
等。 - 調(diào)用dispose方法,完成整個(gè)過程。
用一張圖來來表示整個(gè)過程
引用
美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì)RACSignal的Subscription深入分析
寫在最后
第一篇ReactiveCocoa的文章,寫的不好,如有寫的不對(duì)的地方,歡迎指正,共同進(jìn)步。謝謝!!!