ReactiveCocoa 更优雅的编程(信号探秘)

作者: Andi | 来源:发表于2017-10-16 12:13 被阅读58次

    ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的框架.

    RAC 的核心思想:创建信号 - 订阅信号 - 发送信号 我们按照这个步骤来 一步一步的实现 并且探寻RAC 里面是怎么的一个原理

    信号写法

    • 第一种写法
     NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
     RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
         NSLog(@"创建信号");
         //发送信号
         [subscriber sendNext:array];  
         return nil;
     }];
     [signal subscribeNext:^(id  _Nullable x) {
          NSLog(@"订阅信号%@",x);
     }];
    
    • 第二种写法 上面的方式缩写
    NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
    [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
          NSLog(@"创建信号");
          //发送信号
          [subscriber sendNext:array];
          return nil;
     }]subscribeNext:^(id  _Nullable x) {
           NSLog(@"订阅信号%@",x);
     }];
    
    • 为了便于理解 我们先按照顺序分步骤写 探寻每个方法里面的秘密

    创建信号 内部的秘密

    • 如我们下面这行代码,就是创建信号。RACSignal 的类方法createSignal,带block回调,里面有一个参数RACSubscriber。整个方法返回一个RACSignal对象。 创因为没有订阅者。称为冷信号
    RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
           NSLog(@"创建信号");
           return nil;
    }];
    

    下面我们进入 createSignal方法看看里面怎么实现的

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

    看到createSignal方法里面 创建了一个 RACDynamicSignal对象,我们可以把它理解为一个动态信号。同时对一个didSubscribe这个block 进行了一个保存

    订阅信号 内部的秘密

    • 订阅信号 RACSignal 对象 调用一个方法 subscribeNext,方法 返回一个RACDisposable对象(可以先不看这个) ,写了subscribeNext 方法的信号,因为有了订阅者称为热信号。
     [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"订阅信号%@",x);
     }];
    

    下面我们进入 subscribeNext 方法看看 里面有什么

    - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
        NSCParameterAssert(nextBlock != NULL);
        
        RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
        return [self subscribe:o];
    }
    //进入subscriberWithNext方法
    + (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;
    }
    

    看到 subscribeNext里 调用subscriberWithNext里面 创建了一个 RACSubscriber 对象(这是一个有意思的现象 ,在上面 创建信号的里面 我们见到了 创建方法里 保存了一个didSubscribe block 也是RACSubscriber,它的实质就是创建信号的block)。同时 对 _next _error _completed 三个block 进行了保存 并执行了RACSubscriber

    发送信号 内部的秘密

    • 就一句简单 sendNext: 如果没有这句,我是订阅者是没法获取数据的
        // 发送信号 
        [subscriber sendNext:@“我是内容”];
    

    下面我们进入 sendNext 方法看看 里面有什么
    sendNext 在 多个类都有此方法

    DF47B9BC-1A2A-4C63-A140-85F7263CC0FB.png

    点击 RACSubject sendNext:
    里面是酱紫的

    - (void)sendNext:(id)value {
        [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
            [subscriber sendNext:value];
        }];
    }
    

    调用 [RACSubject sendNext] 时
    RACSubject就会遍历一遍自己的subcribers数组,并调用各数组元素(subscriber)准备好的Block
    继续点击RACSubscriber sendNext

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

    又见到了 熟悉的面孔 上面 订阅信号保存的一个_next block ,
    把 之前在订阅信号保存的_next block 进行赋值并执行。

    整理一下

    看了一会 这么多方法,这些貌似有联系,但是又模模糊糊的。我们和代码结合起来看

     NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
    一. //创建信号
    1.创建了一个 RACDynamicSignal
    2.保存了一个 didSubscribe block
     RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
         NSLog(@"创建信号");
         三.//发送信号
        1.执行订阅信号保存的_next block 。
         [subscriber sendNext:array];  
         return nil;
     }];
    二.//订阅信号
    1.保存了_next _error _completed 三个block 
    2.执行创建信号时所保存的didSubscribe block
     [signal subscribeNext:^(id  _Nullable x) {
          NSLog(@"订阅信号%@",x);
     }];
    

    看了大约能明白 都是block 在互相关联
    我们在用图了解一些整个信号的运行原理

    E8278B36-AA87-43B1-99A1-AF1E58B11218.png

    创建信号 - 订阅信号 - 发送信号 就是这样实现的
    不得不佩服ReactiveCocoa 的作者们,给我们在开启了一座新的大门。它的编程思想真的值得我们去学习一下。

    结尾:水平有限,代码也很烂,一直在努力学习中,大家多多包涵。

    相关文章

      网友评论

        本文标题:ReactiveCocoa 更优雅的编程(信号探秘)

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