美文网首页
iOS RAC的实现原理3-RACSubject

iOS RAC的实现原理3-RACSubject

作者: Onlyoner | 来源:发表于2017-06-15 17:47 被阅读0次

RACSubject 信号提供者!!,自己可以充当信号,又能够发送信号!!

首先回顾一下

     RACDisposable:它可以帮助我们取消订阅.信号发送完毕了 ,失败了.
     
     RACSubscriber(协议):订阅者(发送信号!)
     
     RACSubject :信号提供者!!,自己可以充当信号,又能够发送信号!!
     

RACSubject:这个类叫做信号提供者,自己可以充当信号,又能够发送信号!!

@interface RACSubject<ValueType> : RACSignal<ValueType> <RACSubscriber>
编程思想:《面向协议的开发》
     
OC里边没有多继承这一说,那么我(RACSubject)想继承另一个类(RACSignal)里的功能:
就需要 我(RACSubject) 遵守 订阅者协议< RACSubscriber >,实现订阅者协议的方法,就可以了。
     
就是面向协议的开发的应用场景。

还是三步走:

1.创建信号
2.订阅信号
3.发送数据
//1.创建信号
    RACSubject *subject = [RACSubject subject];
    
    //2.订阅信号
    //不同的信号订阅的方式不一样!!因为类型不一样,所以调用的方法不一样。
    //RACSubject处理订阅 :拿到之前的_subscribers 保存订阅者
    [subject subscribeNext:^(id  _Nullable x) {
      
        NSLog(@"接收到的数据 x 是 %@",x);
        
    }];
    
    
    
    //3.发送数据
    //遍历出所有的订阅者,其实还是调用的nextBlock
    [subject sendNext:@"数据A"];

打印的结果:

2017-06-15 16:18:54.468 RAC-demo[41104:6465743] 接收到的数据 x 是 数据A

多订阅者

//1.创建信号
    RACSubject *subject = [RACSubject subject];
    
    //2.订阅信号
    //不同的信号订阅的方式不一样!!因为类型不一样,所以调用的方法不一样。
    //RACSubject处理订阅 :拿到之前的_subscribers 保存订阅者
    [subject subscribeNext:^(id  _Nullable x) {
      
        NSLog(@"订阅1⃣️ 接收到的数据 x 是 %@",x);
        
    }];
    [subject subscribeNext:^(id  _Nullable x) {
        
        NSLog(@"订阅2⃣️ 接收到的数据 x 是 %@",x);
        
    }];
    
  
    //3.发送数据
    //遍历出所有的订阅者,其实还是调用的nextBlock
    [subject sendNext:@"数据A"];

打印的结果:

2017-06-15 17:04:56.804 RAC-demo[41379:6621767] 订阅1⃣️ 接收到的数据 x 是 数据A
2017-06-15 17:04:56.805 RAC-demo[41379:6621767] 订阅2⃣️ 接收到的数据 x 是 数据A

实现原理

1、创建信号
订阅管理者(_disposable)、保存订阅者的数组(_subscribers)

" cmd "点"subject"进去
" [RACSubject subject] "

// This should only be used while synchronized on `self`.
@property (nonatomic, strong, readonly) NSMutableArray *subscribers;

// Contains all of the receiver's subscriptions to other signals.
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;

+ (instancetype)subject {
    return [[self alloc] init];
}

- (instancetype)init {
    self = [super init];
    if (self == nil) return nil;

    _disposable = [RACCompoundDisposable compoundDisposable];
    _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
    
    return self;
}

- (void)dealloc {
    [self.disposable dispose];
}
作者在重写的init方法里面进行了创建信号订阅管理者(_disposable)、保存订阅者的数组(_subscribers),
便于多个订阅者订阅
"_disposable"、"_subscribers"

2、订阅信号
RACSubject处理订阅 :拿到之前的_subscribers 保存订阅者

"cmd"点"subscribeNext "进去
" [subject subscribeNext:^(id  _Nullable x) {}] "

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

保存Block
nextBlock

注意" [self subscribe:o] "
"cmd"点"subscribe "进去
此处的"self"代表的是"RACSubject"

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    NSMutableArray *subscribers = self.subscribers;
    @synchronized (subscribers) {
        [subscribers addObject:subscriber];
    }
    
    [disposable addDisposable:[RACDisposable disposableWithBlock:^{
        @synchronized (subscribers) {
            // Since newer subscribers are generally shorter-lived, search
            // starting from the end of the list.
            NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
                return obj == subscriber;
            }];

            if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
        }
    }]];

    return disposable;
}

保存所有订阅者
[subscribers addObject:subscriber];

#@synchronized上锁的原因是:@synchronized() 的作用是:
#创建一个互斥锁,保证在同一时间内没有其它线程对self对象进行修改,起到线程的保护作用,
#一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。

这里把订阅管理者disposable返回出去便于 手动 取消订阅

3、发送数据
遍历出所有的订阅者,其实还是调用的nextBlock

"cmd"点"sendNext"进去
"[subject sendNext:@"数据A"]"

- (void)sendNext:(id)value {
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
        [subscriber sendNext:value];
    }];
}
看到"enumerateSubscribersUsingBlock"就知道这是个循环,
就是要把之前保存的订阅者一个一个找出发送信号
#下边这个方法证实了这个的想法:
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
    NSArray *subscribers;
    @synchronized (self.subscribers) {
        subscribers = [self.subscribers copy];
    }

    for (id<RACSubscriber> subscriber in subscribers) {
        block(subscriber);
    }
}
#block(subscriber);
block一调用就近到了"[subscriber sendNext:value];"方法
#pragma mark RACSubscriber

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

        nextBlock(value);
    }
}
#看到了熟悉的
nextBlock(value);
这就表示在这里进行了发送数据把保存的nextBlock一执行就实现了数据返回后的处理了。

流程图示:


实现原理图示.png

相关文章

网友评论

      本文标题:iOS RAC的实现原理3-RACSubject

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