ReactiveCocoa框架理解一

简介

ReactiveCocoa是一个基于函数响应式编程思想(Funcation Reactive Programming,简称FRP)的框架。由几个重要的部分组成,如下:

信号:例如RACSignal,他可以被订阅,订阅后进行逻辑处理或者数据传递。

订阅者:例如RACSubscriber,表示订阅者的意思。用于订阅和发送数据。它是一个协议,由具体的类实现。

清理者:例如RACDisposable,用于取消或者清理订阅者的资源。

RACSubject:可以当成一个信号,也可以充当信号发送者。

一个简单的流程分析

最基本的流程可以是,创建一个信号,然后创建一个订阅者并且订阅这个信号。

//首先创建一个信号
RACSignal *signal = [RACSignal create:^(id subscriber) {
    [subscriber sendNext:@"test"]; //被subscriber订阅后,触发subscriber的sendNext方法,传递数据
}];    
[signal subscribeNext:^(id x) {
    NSLog(x); //将传递的数据数据输出
}];
//输出"test"

//创建一个RACDynamicSignal信号,指定了被订阅后的回调逻辑
+ (RACSignal *)create:(void (^)(id))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)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)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 
@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作为响应,传递数据,在写法上使代码高聚合,方便管理。

你可能感兴趣的:(ReactiveCocoa框架理解一)