美文网首页
RAC信号和订阅

RAC信号和订阅

作者: 高思阳 | 来源:发表于2019-05-15 11:37 被阅读0次

RAC中创建一个新的信号的方法:

//代码段(1)
RACSignal *newSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
}];

点进去,可以查看RACSignal里面createSignal:方法的实现,是直接调用的RACDynamicSignalcreateSignal: 方法,RACDynamicSignal是一个继承自RACSignal的类。

//代码段(2)
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}

根据代码段(2),我们可以修改代码段(1),如下:

//代码段(3)
//didSubscribe这个block就是代码段(1)后面展开的block
RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber) = ^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
};

//[RACSignal createSignal:didSubscribe]; 内部直接 return [RACDynamicSignal createSignal:didSubscribe];
RACSignal *newSignal =  [RACDynamicSignal createSignal:didSubscribe]; 

查看RACDynamicSignal类中createSignal:方法的实现:

//代码段(4)
@interface RACDynamicSignal ()
@property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber);
@end

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}

代码段(4)就是创建了一个RACDynamicSignal对象,并且把didSubscribe这个block,赋值给该对象属性didSubscribe对应的实例变量_didSubscribe,然后给该对象设置name属性为@"+createSignal:"

这里我们再重新指出:RACDynamicSignal继承自RACSignal,RACSignal继承自RACStream。

根据代码段(4),我们可以修改代码段(3),如下:

代码段(5)
RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber) = ^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
};

//RACDynamicSignal继承自RACSignal
RACSignal *newSignal =  [[RACDynamicSignal alloc]init]; 
newSignal->_didSubscribe = didSubscribe;

//setNameWithFormat:方法是RACStream中的方法,而RACSignal继承自RACStream
[newSignal setNameWithFormat:@"+createSignal:"];

这里将子类RACDynamicSignal赋值给父类RACSignal。需要说明一点:继承是将父类的方法与属性继承给了子类,所以子类不用重复声明。同时子类也能声明自己的方法与属性。这些子类声明的方法与属性是父类没有的。所以可以通过子类给父类赋值,因为父类有的子类都有。不能通过父类给子类赋值,因为子类自己独有的方法与属性父类没有,当通过父类去访问子类独有的方法和属性的时候就会报错。

到此,信号的创建已经看完了。接下来看看信号的订阅。

信号订阅的方法如下:

代码段(6)
[newSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
}];

把代码段(6)改一下:

代码段(7)
void (^nextBlock)(id x) = ^(id  _Nullable x) {
        NSLog(@"%@",x);
};

[newSignal subscribeNext:nextBlock];

点进subscribeNext:方法:

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];

    //这里调用的是RACDynamicSignal的subscribe:方法,因为代码段(5)中,RACSignal *newSignal =  [[RACDynamicSignal alloc]init]; 
    //把RACSignal对象赋值为其子类RACDynamicSignal对象,所以调用的就是它的子类对象的方法,而不是自己内部的方法。
    return [self subscribe:o];
}

+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
    RACSubscriber *subscriber = [[self alloc] init];

    subscriber->_next = [next copy];
    subscriber->_error = [error copy];
    subscriber->_completed = [completed copy];

    return subscriber;
}

- (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);// 调用了`didSubscribe`这个block
            [disposable addDisposable:innerDisposable];
        }];

        [disposable addDisposable:schedulingDisposable];
    }
    
    return disposable;
}

这个方法里面创建了一个RACSubscriber对象,并且在该对象内部保存了三个block到对应的实例变量中,分别是_next_error_completed三个block变量,我们这里_next保存了代码段(7)的nextBlock,而剩下两个实例变量只是保存了NULL。
我们可以看到- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber方法中第六行(已标注,对应代码 self.didSubscribe(subscriber)),调用了didSubscribe这个block。

综上,信号被订阅(调用subscribeNext:方法)的时候,didSubscribe这个block被调用,也就是newSignal中的_didSubscribe(对应的就是代码段(2)的didSubscribe)这个block被调用。

接下来看看

[subscriber sendNext:@(1)];

- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;
        nextBlock(value);
    }
}

这里调用了上面RACSubscriber对象_next实例变量的nextBlock(代码段(7)的nextBlock),此时就相当于订阅者收到了消息。

总结:

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe //①
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock //②
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber //③
- (void)sendNext:(id)value //④

使用 方法① 创建信号RACSignal对象的时候,实际内部创建了一个子类对象RACDynamicSignal,在这个子类对象中保存了 方法① 后面的didSubscribe(block块),然后将这个对象返回。

使用 方法② 订阅信号RACSignal对象的时候,内部生成一个subscriber(订阅者对象RACSubscriber对象)。这个订阅者对象用实例变量_next保存了传进来的参数nextBlock(类似方法还会保存一个errorBlock和一个completedBlock)。并且信号RACSignal对象(实际保存的是子类对象RACDynamicSignal)调用 方法③方法③ 内部调用了 方法① 中被保存的 didSubscribe(block块),并且把订阅者对象当做block的参数传了过去。

方法① 中使用上面通过didSubscribe(block块)传进来的subscriber(订阅者对象)调用 方法④方法④ 内部调用了subscriber(订阅者对象)里面保存的那个nextBlock(上面_next中保存的block)。

相关文章

  • RAC信号和订阅

    RAC中创建一个新的信号的方法: 点进去,可以查看RACSignal里面createSignal:方法的实现,是直...

  • 01-ReactiveObjC使用记录

    RAC 的核心思想:创建信号 - 订阅信号 - 发送信号 ,并且在 RAC 中我们会看到大量的 block RAC...

  • iOS-RAC综述

    上一篇我们探索了RAC的核心流程就是: 创建信号 订阅信号 订阅者发送信号 销毁 那么我们根据这些操作来看看RAC...

  • RAC基本用法

    1.信号的创建、订阅和发送 1.1创建信号 1.2 订阅信号 1.3 合并到一块的写法 2.RAC信号的监听 2....

  • RAC简单示例

    RAC简单示例 信号订阅与发送 使用示例

  • rac 事件概述及处理

    概述:想要知道rac就必须知道rac中的三个要点 创建信号、发送信号、订阅信号。 reactive事件 reac...

  • ReactiveCocoa 信号

    信号源 在RAC中,信号源代表等是随着时间而改变的值流,这是对RAC最精准的概括。订阅者可以通过订阅信号源来获取这...

  • ReactiveCocoa解读-订阅信号

    信号(Signal)和订阅者(Subscriber)是在ReactiveCocoa( 下文简称RAC)的相关资料中...

  • iOS ReactiveCocoa学习笔记(2):底层探究

    参考资料:《RAC基础:信号和订阅者模式》、《可变的热信号 RACSubject》 本文知识点:探究 RACSig...

  • RAC响应式框架的api文档

    RAC内存管理 RAC会维护一个全局的信号集合,一个或多于一个订阅者就可用,所有订阅者都被移除了,信号就被释放了。...

网友评论

      本文标题:RAC信号和订阅

      本文链接:https://www.haomeiwen.com/subject/jeauaqtx.html