ReactiveCocoa框架理解一
简介
ReactiveCocoa是一个基于函数响应式编程思想(Funcation Reactive Programming,简称FRP)的框架。由几个重要的部分组成,如下:
信号:例如RACSignal,他可以被订阅,订阅后进行逻辑处理或者数据传递。
订阅者:例如RACSubscriber,表示订阅者的意思。用于订阅和发送数据。它是一个协议,由具体的类实现。
清理者:例如RACDisposable,用于取消或者清理订阅者的资源。
RACSubject:可以当成一个信号,也可以充当信号发送者。
一个简单的流程分析
最基本的流程可以是,创建一个信号,然后创建一个订阅者并且订阅这个信号。
//首先创建一个信号
RACSignal *signal = [RACSignal create:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"test"]; //被subscriber订阅后,触发subscriber的sendNext方法,传递数据
}];
[signal subscribeNext:^(id x) {
NSLog(x); //将传递的数据数据输出
}];
//输出"test"
//创建一个RACDynamicSignal信号,指定了被订阅后的回调逻辑
+ (RACSignal *)create:(void (^)(id<RACSubscriber>))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+create:"];
}
//创界一个订阅者,并且订阅信号
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock {
RACLiveSubscriber *subscriber = [RACLiveSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];
subscriber.signal = self; //subscriber关联信号
[self attachSubscriber:subscriber]; //信号被subscriber订阅
return subscriber.disposable;
}
1.create:方法创建一个RACDynamicSignal类型的信号signal,并且指定了被订阅后的回调逻辑。
2.创建一个RACLiveSubscriber类型的订阅者subscriber,subscriber分别维护了3个block,用于处理next事件,error事件和completed事件的数据,本例的error和completed回调均为nil。
3.subscriber订阅signal,RACDynamicSignal类型的信号在attachSubscriber方法中会触发_didSubscribe回调,并传入subscriber。在回调逻辑里,subscriber触发next事件,传递数据。
4.subscriber的next回调接收到数据后,输出。
订阅方法
RACSignal信号类提供了一系列订阅信号的方法,但都是基于上文的subscribeNext:error:completed:,例如:
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
return [self subscribeNext:nextBlock error:nil completed:nil];
}
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock {
return [self subscribeNext:nextBlock error:nil completed:completedBlock];
}
- (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock {
return [self subscribeNext:nil error:errorBlock completed:nil];
}
- (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock {
return [self subscribeNext:nil error:nil completed:completedBlock];
}
还有一个较为不同的方法是:
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
RACLiveSubscriber *liveSubscriber;
if (subscriber == nil) {
//创建一个RACLiveSubscriber,维护三个block,即next、error和completed,但只都是nil
liveSubscriber = [RACLiveSubscriber subscriberWithNext:nil error:nil completed:nil];
} else {
//创建一个RACLiveSubscriber,维护三个block,即next、error和completed
liveSubscriber = [RACLiveSubscriber subscriberForwardingToSubscriber:subscriber];
}
liveSubscriber.signal = self;
[self attachSubscriber:liveSubscriber];
return liveSubscriber.disposable;
}
该方法根据一个已有的subscriber,套一个新的RACLiveSubscriber类型的liveSubscriber在外面,liveSubscriber内部的next、error和completed回调会触发原subscriber的对应回调。
+ (instancetype)subscriberForwardingToSubscriber:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
//新liveSubscriber的三个block分别去调用原subscriber的三个block
RACLiveSubscriber *liveSubscriber = [self subscriberWithNext:^(id x) {
[subscriber sendNext:x];
} error:^(NSError *error) {
[subscriber sendError:error];
} completed:^{
[subscriber sendCompleted];
}];
[subscriber.disposable addDisposable:liveSubscriber.disposable];
[liveSubscriber.disposable addDisposable:[RACDisposable disposableWithBlock:^{
[subscriber.disposable removeDisposable:liveSubscriber.disposable];
}]];
return liveSubscriber;
}
将新liveSubscriber的disposable加入原subscriber的disposable队列中,关联两者的disposable对象。
RACDisposable
RACDisposable相关类负责清理订阅者的资源,例如创建一个RACDisposable的方法:
RACDisposable *disposable = [RACDisposable disposableWithBlock:^{
//...执行相关逻辑
}];
disposable对象里面维护一个block,当执行dispose方法时,会执行block。RACCompoundDisposable对象是RACDisposable对象的子类,作用是维护一个队列,里面存放了若干个disposable对象,RACCompoundDisposable对象执行dispose方法时,将队列中的disposable对象依次执行dispose方法。
和订阅者结合使用情况下,每个订阅者会维护一个RACCompoundDisposable对象disposable,如下:
@protocol RACSubscriber <NSObject>
@required
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
- (void)sendNext:(id)value;
- (void)sendError:(NSError *)error;
- (void)sendCompleted;
@end
除了实现三个事件触发的方法,还有一个RACCompoundDisposable对象disposable,以RACLiveSubscriber为例,在初始化的时候会创建一个RACCompoundDisposable对象,如下:
- (id)init {
...
//创建一个selfDisposable对象,用于将三个事件block置为nil
RACDisposable *selfDisposable = [RACDisposable disposableWithBlock:^{
@strongify(self);
if (self == nil) return;
OSSpinLockLock(&self->_spinLock);
self.next = nil;
self.error = nil;
self.completed = nil;
OSSpinLockUnlock(&self->_spinLock);
}];
//将selfDisposable对象加入队列对象中
_disposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ selfDisposable ]];
return self;
}
接着分析上面的subscriberForwardingToSubscriber:方法
[subscriber.disposable addDisposable:liveSubscriber.disposable];
[liveSubscriber.disposable addDisposable:[RACDisposable disposableWithBlock:^{
[subscriber.disposable removeDisposable:liveSubscriber.disposable];
}]];
将新的liveSubscriber对象的disposable对象加入原subscriber对象的disposable队列中。之所以这样做,我的理解是liveSubscriber基于subscriber创建,因此当subscriber在某种情况dispose,相关联的liveSubscriber失去存在意义,也要dispose,将其三个事件的block置为nil,同时将liveSubscriber的disposable对象从队列中移除。
attachSubscriber:
attachSubscriber:负责signal被订阅后的逻辑,基类RACSignal默认不实现任何功能,如下:
- (void)attachSubscriber:(RACLiveSubscriber *)subscriber {
NSCAssert(NO, @"This method must be overridden by subclasses.");
}
不同的signal子类实现逻辑不一样,以create:方法创建的RACDynamicSignal类为例,如下:
- (void)attachSubscriber:(RACLiveSubscriber *)subscriber {
NSCParameterAssert(subscriber != nil);
if (self.didSubscribe != NULL) { //执行signal的_didSubscribe回调
self.didSubscribe(subscriber);
}
}
以RACReturnSignal类为例,如下:
- (void)attachSubscriber:(RACLiveSubscriber *)subscriber {
NSCParameterAssert(subscriber != nil);
[subscriber sendNext:self.value]; //触发subscriber的next事件,将value作为数据传递
[subscriber sendCompleted]; //触发subscriber的comple事件
}
总结
RAC框架通过block回调的方式实现FRP编程思想,每一次操作会触发一个对应的block作为响应,传递数据,在写法上使代码高聚合,方便管理。