iOS ReactiveObjc框架解析

简介

ReactiveObjc将原有的各种设计模式,包括代理、Target/Action、block、通知中心以及观察者模式各种『输入』,都抽象成了数据流或者信号(也可以理解为状态流)让单一的组件能够对自己的响应动作进行控制,简化了视图控制器的负担。ReactiveObjc整个框架主要是围绕Signal来运转。
我们先来看一段代码

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"释放");
        }];
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

这段代码的打印

2021-04-12 15:15:31.988297+0800 ZLXStudyDemo[64724:7390883] 1
2021-04-12 15:15:31.988485+0800 ZLXStudyDemo[64724:7390883] 2
2021-04-12 15:15:31.988587+0800 ZLXStudyDemo[64724:7390883] 3
2021-04-12 15:15:34.694916+0800 ZLXStudyDemo[64724:7390883] 释放

这段代码包含ReactiveObjc的信号完成使用逻辑。
我们先大致分析下:通过RACSignal的createSignal:创建一个signal->signal通过subscribeNext:订阅一个信号-> RACSubscriber通过sendNext来触发订阅的信号

下面我们从以下四方来解析上述过程的原理:

  • 信号的创建
  • 信号的订阅
  • 订阅的响应
  • 订阅的回收

信号的创建

RACSignal是ReactiveObjc框架信号处理的核心。信号的创建我们主要来看下这个类。

先看下创建相关的代码:

// step1
 RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"释放");
        }];
    }];

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

信号的创建是不是非常简单。

  • RACSignal调用create内部再调用RACDynamicSignal的create
  • RACDynamicSignal将传入Subscribeblock绑定到RACDynamicSignal的didSubscribe属性上。


    image.png

所以整个信号的订阅我们可以理解为:绑定信号关联的block到RACDynamicSignal的didSubscribe属性上
这个关联的block什么时候触发呢? 怎么触发的呢? 接下来我们来看下信号的订阅。

信号的订阅

ReactiveObjc订阅的相关逻辑我们主要看RACSubscriber

订阅相关的代码:

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

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

//step3
+ (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;
}

//step4
- (RACDisposable *)subscribe:(id)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);
            [disposable addDisposable:innerDisposable];
        }];

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

我们来分析下订阅的过程:

  • RACSignal调用订阅API,传入订阅的block
  • 创建RACSubscriber,并绑定上一步的block
  • RACSignal调用subscribe,传入上一步创建的RACSubscriber,
  • 调用之前RACSignal信号创建时候绑定的didSubscribe,并传入上一步传入的RACSubscriber

让我们在看看看刚开始的代码,现在知道[subscriber sendNext:@"1"];这个subscriber是什么时候创建的了吗?上面的步骤2

RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
// 这个subscriber什么时候创建的呢?
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"释放");
        }];
    }];
image.png

订阅的响应

//step1 调用sendNext
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"释放");
        }];
    }];
//step2 调用nextBlock
- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);
    }
}
// 响应block
[signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x); 
}];

这个流程是不是很简单。给你个问题 nextblock哪里来的?

订阅的取消

RACDisposable 是订阅回收的核心。主要思想是用来处理异步的操作。
每一个异步操作关联一个RACDisposable,当执行操作的时候,去check RACDisposable的状态。

我们来看下之前的订阅代码

- (RACDisposable *)subscribe:(id)subscriber {
    NSCParameterAssert(subscriber != nil);
//step1 创建一个容器disposable,可以同时处理多个disposable
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
//消息转发。主要作用是check disposable状态
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    if (self.didSubscribe != NULL) {
//step2
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
//step3
            [disposable addDisposable:innerDisposable];
        }];
//step4
        [disposable addDisposable:schedulingDisposable];
    }
    
    return disposable;
}

我们来看下代码吧,每次执行操作的时候都去check下disposed。

- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);

    RACDisposable *disposable = [[RACDisposable alloc] init];

    dispatch_async(self.queue, ^{
        if (disposable.disposed) return;
        [self performAsCurrentScheduler:block];
    });

    return disposable;
}

// RACSubscriber 释放调用挂载的RACDisposable的block
- (void)dealloc {
    [self.disposable dispose];
}

你可能感兴趣的:(iOS ReactiveObjc框架解析)