ReactiveCocoa信号发送详解
简介
ReactiveCocoa 是一个重型的 FRP (Functional Reactive Programming 是一种响应变化的编程范式) 框架。内部使用了大量的block。FRP的核心就是信号。
RACSignal就是信号,是ReactiveCocoa中很重要的一个概念。RACSignal本体是RACStream。信号就是数据流,可以用来传递和绑定。
以下代码基于V2.5的ReactiveCocoa
创建RACsignal
不说废话,先来一张图
RACSignal.png// 源码
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
通过RACDynamicSignal
创建信号,此时传入一个block,这个block的参数是一个遵循RACSubscriber
协议的一个变量,同时这个block的返回值是一个RACDisposable
类型。
通过源码分析,看到RACDynamicSignal
有一个属性didSubscribe
存储了传进来的的block,这个属性将在之后订阅的时候使用。
这个RACSubscriber的协议,其中定义了几个方法
@protocol RACSubscriber <NSObject>
@required
// 发送next需要执行的参数
- (void)sendNext:(id)value;
// 发送错误
- (void)sendError:(NSError *)error;
// 发送成功
- (void)sendCompleted;
// 处理信号,是否释放取消订阅。
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end
创建一个信号
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
}];
}];
订阅
一个信号通过调用subscribeNext
创建一个subscriber进行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];
}
// 当前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;
}
-
源码中创建了一个RACSubscriber来存储nextBlock、error、completed。然后订阅处理subscription。
-
这里有一个
RACCompoundDisposable
,这是一个RACDisposable
,只不过RACCompoundDisposable
可以存放多个RACDisposable
。当RACCompoundDisposable 执行dispose方法时,它所存放的disposable都会被释放。 -
使用
RACPassthroughSubscriber
将当前的订阅者进行转化,转化为另外一种形式的订阅者。这个订阅者中存储了当前的订阅者,信号、disposable。存储了一个信号的完整处理,并且这个订阅者同样遵循<RACSubscriber>协议。这里可以把RACPassthroughSubscriber当成是订阅者的装饰器(伪装器)。 -
使用RACPassthroughSubscriber的目的是将subscirber传递给另一个还没有disposed的subscriber。
Passes through all events to another subscriber while not disposed.
-
当执行self.didSubscribe(subscriber)时siganle存储的block就会被执行。当sendNext:执行时,先执行[RACPassthroughSubscriber sendNext:],然后调用RACPassthroughSubscriber中的subscriber来执行
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];
}
继续执行
addDisposable,此时会将
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.
// 会在此处释放。
if (shouldDispose) [disposable dispose];
}
6. 源码中可以看出,订阅一个信号,返回的是一个RACDisposable,作为一个返回值返回到外部,我们可以在外部对其取消这个订阅。
###总结
```objc
// part 1.
RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 此处subscriber为转换后的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);
}];
- 调用createSignal:创建一个信号。存储当前的block到didSubscribe这个block中。
- 调用subscribeNext:订阅信号。创建一个subscriber来subscription。在subscriber中存储nextBlock,errorBlock,completeBlock三个block。
- 当前的订阅通过转换,成为RACPassthroughSubscriber,这个subscriber中有三个重要的属性分别是当前订阅的subscriber,当前的signal和RACCompoundDisposable。
- RACDynamicSignal执行
didSubscribe(RACPassthroughSubscriber)
这个block。执行RACPassthroughSubscriber中的sendNext:, sendError:, sendCompeleted
。 - RACPassthroughSubscriber中通过判断当前的disposable的状态来判断是否告诉subscriber调用相应的
sendNext:
等。 - 调用dispose方法,完成整个过程。
用一张图来来表示整个过程
ReactiveCocoa.jpg
引用
美团点评技术团队RACSignal的Subscription深入分析
写在最后
第一篇ReactiveCocoa的文章,写的不好,如有写的不对的地方,欢迎指正,共同进步。谢谢!!!