美文网首页
RAC 之 RACSignal 使用与源码分析

RAC 之 RACSignal 使用与源码分析

作者: LoZR | 来源:发表于2019-06-12 14:22 被阅读0次

RACSignal 使用

   // 1 创建信号
    @weakify(self)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        @strongify(self)
        self.subsrcribe = subscriber;

        // 3 发送信号
        [subscriber sendNext:@"hahah"];

        return [RACDisposable disposableWithBlock:^{
            NSLog(@"销毁了");
        }];
    }];

    // 2 订阅信号
    [signal subscribeNext:^(id  _Nullable x) {
        // 第 3 步 发送信号后, 此处 block 会被回调
        NSLog(@"subscribeNext:%@",x);
    }];

根据上述代码流程,RACSignal 的使用分别有 3 步

  • 创建:实例一个 RACSignal对象,并实现一个能够获取 subscriber 订阅者的 block
  • 订阅:使用RACSignal对象进行订阅,用于获取发送信号后的回调结果
  • 发送信号:使用subscriber 订阅者在特定位置发送信号(发送结果),订阅信号的 block 获取结果

一、RACSignal 的创建

以下我们开始分析一下 RACSignal类型的对象是怎么来的

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        return [RACDisposable disposableWithBlock:^{
            
        }];
    }];

上述RACSignal 的创建 方法,

//  RACSignal.h
+ (RACSignal<ValueType> *)createSignal:
(RACDisposable * _Nullable (^)(id<RACSubscriber> subscriber))didSubscribe
//  RACSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
     //RACDynamicSignal 继承于 RACSignal
    return [RACDynamicSignal createSignal:didSubscribe];
}

因为返回的是 RACSignal类型,却使用了

return [RACDynamicSignal createSignal:didSubscribe];

由此可得 RACDynamicSignal 这个子类做了一系列的实例化和包装处理,如下:

//RACDynamicSignal.m

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
        //  setNameWithFormat: 进行了一些列的底层打印日志操作,
       //   最后还是返回了一个 RACSignal 的对象
    return [signal setNameWithFormat:@"+createSignal:"];
}

二、RACSignal 订阅信号

    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext:%@",x);
    }];

上述方法是在 RACSignal (Subscription)类别里的一个方法:

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    // 创建 subscribe 对象 并保存 Next、Error、Completed 三个Block
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    // 传入 subscribe 并创建 disposable
    return [self subscribe:o];
}

RACSubscriber的对象主要保存了 Next、Error、Completed 3个Block,再往里面跟一层如下:

// RACSubscriber.m
+ (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;
}

然后回到 上面的类别: RACSignal (Subscription)

  return [self subscribe:o];

上述方法虽然是在本类别里调用

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCAssert(NO, @"This method must be overridden by subclasses");
    return nil;
}

但却被子类 RACDynamicSignal 重写了

// RACDynamicSignal.m
#pragma mark Managing Subscribers
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    // 传入 subscribe 并创建 disposable,
    // 复合销毁者
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    
    /**
     *  subscriber --- RACSubscriber
     *  signal     --- self 
     *  disposable
     */

    //  新的(RACPassthroughSubscriber*)subscriber 拥有:disposable、signal、subscribe 三者合成
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    // signal 有执行 didsubscribe Block 往下走
    if (self.didSubscribe != NULL) {
        
        //  这里需要注意!!!!  如果开启了异步操作,RACScheduler.subscriptionScheduler 的类型是 “RACTargetQueueScheduler” 并在子线程执行 【RACTargetQueueScheduler schedule:】
        
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            // 这一步 self.didSubscribe(subscriber) 进行block 回调出去
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            // 添加销毁
            [disposable addDisposable:innerDisposable];
        }];

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

上述代码我们主要看订阅者subscriber 的回调流程:

// 只要外部执行了
[RACSignal  createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
  // 这里得到 subscriber 的底层回调
}

 当底层使用 self.didSubscribe(subscribe) 就会回调出去上面的代码块里

小结一下整个订阅过程主要做了的就是:
signal 订阅了 subscribeNext:^(id _Nullable x) 的 block,并内部配置了 subscribe,即:

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

此时 subscriber拥有了下面 signal的block 实现

// 三种订阅原理都是一样
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext:%@",x);
     }];

    [signal subscribeError:^(NSError * _Nullable error) {
        NSLog(@"subscribeError");
    }];

    [signal subscribeCompleted:^{
        NSLog(@"subscribeCompleted");
    }];

下一步subscriber 就可以根据不同场景发送信号进行 block 回调了

三、 RACSignal 发送信号

使用subscriber发送信号:

        [subscriber sendNext:@"hahah"];
    
        [subscriber sendError:nil];

        [subscriber sendCompleted];
// RACSubscriber.m
#pragma mark RACSubscriber

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

- (void)sendError:(NSError *)e {
    @synchronized (self) {
        void (^errorBlock)(NSError *) = [self.error copy];
        // 在回调 block 之前 ,执行了销毁方法
        [self.disposable dispose];

        if (errorBlock == nil) return;
        errorBlock(e);
    }
}

- (void)sendCompleted {
    @synchronized (self) {
        void (^completedBlock)(void) = [self.completed copy];
        // 在回调 block 之前 ,执行了销毁方法
        [self.disposable dispose];

        if (completedBlock == nil) return;
        completedBlock();
    }
}

上面 subscriber 根据不同方法分别调用了 nextBlock(value),errorBlock(e),completedBlock() 使得第二步 signal的订阅信号得到了回调结果;

值得注意的是:

- (void)sendError:(NSError *)e
- (void)sendCompleted;

这两个方法的实现里,分别都调用了

[self.disposable dispose];

这部操作把 subscriber进行了销毁, 之后的subscriber如果再调用 sendNext, sendError , sendCompleted 或其他发送信号的方法,都已经失效了。

关于 RACSignal,RACSubscriber 就暂时介绍到这里,上述涉及到RACDisposable,RACScheduler 没有作出过多的解释,后续抽时间会继续写下去。

以上内容纯粹个人见解,仅用于分享交流;如有描述不当之处,欢迎指出。

相关文章

  • RAC 之 RACSignal 使用与源码分析

    RACSignal 使用 根据上述代码流程,RACSignal 的使用分别有 3 步 创建:实例一个 RACSi...

  • RAC的基本使用

    RAC的基本使用 在RAC中,一切都是信号! RACSignal RACSignal实例化一个信号,首先,需要创建...

  • RAC源码解析

    RAC是一个函数响应编程框架。 先来一个简单的RAC使用: RACSignal使用步骤:1.创建信号 + (RAC...

  • RAC框架源码解析之RACSignal

    1、RACSignal RacSignal是一个信号类!有如下几个特点: 通过RACSignal创建出来的信号默认...

  • RACSignal介绍

    RACSignal 在RAC中最核心的类RACSignal,搞定这个类就能用ReactiveCocoa了。 RAC...

  • (一)、iOS RAC - RACSignal

    (一)、iOS RAC - RACSignal (二)、iOS RAC - RACDisposable(三...

  • ReactiveCocoa源码与坑

    在阅读源码之前容我抛出个小问题,看看下面的代码? 这是公司项目中对RAC的一段使用,生成的RACSignal实例自...

  • ReactiveObjC (一)

    RAC 看似使用简单,代码紧凑,但不太容易精通,这里做一个简单汇总。 RAC 框架中的主要类 RACSignal ...

  • RAC之RACSignal,RACSubject, RACSeq

    学习RAC先从熟悉简单类的使用开始,RACSignal信号类,使用方法:(1)createSignal创建信号类(...

  • ReactiveObjC使用

    一.RAC基础使用 监听方法调用 KVO 通知 监听View事件 监听Timer RACSignal RACSig...

网友评论

      本文标题:RAC 之 RACSignal 使用与源码分析

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