RAC常见用法(三)

作者: 小冰山口 | 来源:发表于2017-05-03 18:03 被阅读232次
    本文将要介绍的RAC的常见用法大纲:
    RAC常见用法(三)
    • RAC的映射:
    - (RACSignal *)flattenMap:(__kindof RACSignal * _Nullable (^)(ValueType _Nullable value))block;
    
    - (RACSignal *)map:(id _Nullable (^)(ValueType _Nullable value))block;
    

    首先看flattenMap:这个方法, 其实这个方法的内部是绑定信号,

    `flattenMap:`内部调用`bind:`

    bind:方法是要返回一个block, 而flattenMap:这个方法是直接返回一个信号, 这个信号直接订阅就能够拿到包装了value的信号:

        RACSubject *subject = [RACSubject subject];
        
        [[subject flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
            return [RACReturnSignal return:value];
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拿到的数据是: %@ ", x);
        }];
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievantest"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:NULL];
                [subject sendNext:dataArray];
            }] resume];
        });
    

    map信号就更为简单: 之前提到过, map:方法可以在block中返回任意类型的对象, 然后再订阅map:方法返回的信号, 就能够拿到这个对象:

        RACSubject *subject = [RACSubject subject];
        
        [[subject map:^id _Nullable(NSArray *value) {
            return [[value.rac_sequence map:^id _Nullable(id  _Nullable value) {
                return [KFCFood kfcFoodWithDictionary:value];
            }] array];
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拿到的结果是: %@ ", x);
        }];
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievantest"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSArray *resultArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:NULL];
                [subject sendNext:resultArray];
            }] resume];
        });
    
    • RAC的组合:

    1.concat:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
           [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievan/signal1"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
               NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
               [subscriber sendNext:dataString];
               [subscriber sendCompleted];
           }] resume];
            return nil;
        }];
        
        RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievan/signal2"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [subscriber sendNext:dataString];
            }] resume];
            return nil;
        }];
        
        [[signalA concat:signalB] subscribeNext:^(id  _Nullable x) {
            NSLog(@"result is = %@", x);
        }];
    }
    

    这种组合方式是用signalA去合并signalB

    [signalA concat:signalB];
    

    还有一种方法是类方法:

        [[RACSignal concat:@[ signalB, signalA, signalC]] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    类方法是将信号放在一个数组里面, 调用顺序跟上面发送信号的顺序是不同的, 调用顺序是信号在数组中的顺序.

    2.then:

        RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievan/signal1"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [subscriber sendNext:dataString];
    //            [subscriber sendCompleted];
            }] resume];
            return nil;
        }];
        
        [[signalA then:^RACSignal * _Nonnull{
            return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
                [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://mockhttp.cn/mock/tsaievan/signal2"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    [subscriber sendNext:dataString];
                    [subscriber sendCompleted];
                }] resume];
                return nil;
            }];
        }] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    上面的代码执行结束后是不会打印任何东西的, 但是我把signalA中的这行代码打开

    [subscriber sendCompleted];
    

    打开之后, 就可以打印了:

    运行结果

    这说明, 必须signalA的信号接收到了, 并且发送信号结束之后, 才可以接收signalB, 且订阅组合信号的时候只接收signalB. 但它们之间是有依赖关系的,signalB的接收依赖于signalA!

    3.merge:

    这个方法和concat有些类似.

    `merge`方法内部实现

    先将需要合并的信号进行遍历, 放到一个可变数组里, 然后再返回一个信号,这个信号中已经做了sendCompleted的处理, 所以在merge:方法里就不需要再sendCompleted了, 而且, 其调用顺序也不再和数组中的顺序有关, 而是和sendNext的顺序有关.

    4.zip

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

    zipWith:会把信号发送的内容打包成一个元祖 :

    运行结果

    同样的, 也有一个类方法zip:, 将信号数组打包:

        [[RACSignal zip:@[signalC, signalB, signalA]] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    打包的顺序就是数组中的的顺序, 而不是信号sendNext:的顺序:

    运行结果

    5.combineLatest

    + (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;
    

    这是一个类方法, 假设现在有这样一个需求,见下图:

    账号密码同时存在,登录按钮才可以点击的需求

    只需要下面的代码就可以搞定

    - (void)viewDidLoad {
        [super viewDidLoad];
        RACSignal *combineSignal = [RACSignal combineLatest:@[_usernameTextField.rac_textSignal, _passwordTextField.rac_textSignal] reduce:^id(NSString *username, NSString *password){
            return @(username.length && password.length);
        }];
        
        RAC(_loginButton,enabled) = combineSignal;
    }
    

    关于reduceBlock:

    The block which reduces the latest values from all the signals into one value. It must take as many arguments as the number of signals given. Each argument will be an object argument. The return value must be an object. This argument must not be nil.

    这个block其实是带参数的, 参数的数目必须等同于信号的数目, 每一个参数都必须为OC对象, 返回值必须是对象(id类型), 这个block不能传空.

    这个参数其实就是信号发送的值, 即sendNext:的值.

    • RAC的过滤

    1.filter:

        [[_usernameTextField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
            return value.length > 3;
        }] subscribeNext:^(NSString * _Nullable x) {
            NSLog(@"%@", x);
        }];
    

    以上代码的意思就是, 当value.length大于3的时候, 才会返回YES, 这个时候才能信号才会发送, 订阅之后才能接收到数据.

    2.ignore:

        RACSubject *subject = [RACSubject subject];
        [[[[subject ignore:@"1"] ignore:@"2"] ignore:@"5"] subscribeNext:^(id  _Nullable x) {
            NSLog(@"过滤后的数据为: %@ ", x);
        }];
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [subject sendNext:@"3"];
        [subject sendNext:@"4"];
        [subject sendNext:@"5"];
    

    运行结果:

    运行结果

    可以看出的是: 过滤掉了1,2,5三个字符串. 但是不能将字符串装到数组里, 然后过滤数组中的所有元素, 只能像这样:

    [[[subject ignore:@"1"] ignore:@"2"] ignore:@"5"];
    

    链式编程的方式一个个忽略.

    3.take:

        RACSubject *subject = [RACSubject subject];
        [[subject take:3] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拿走的数据是 :%@ ", x);
        }];
        
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [subject sendNext:@"3"];
        [subject sendNext:@"4"];
        [subject sendNext:@"5"];
    

    这个方法表示从前往后, 拿走前三个信号发送的值.

    但是, 如果把代码改成这样:

        RACSubject *subject = [RACSubject subject];
        [[subject takeLast:3] subscribeNext:^(id  _Nullable x) {
            NSLog(@"拿走的数据是 :%@ ", x);
        }];
        
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [subject sendNext:@"3"];
        [subject sendNext:@"4"];
        [subject sendNext:@"5"];
    

    却无法拿到最后三个值, 这是为什么呢? 因为你没有告诉信号, 你发送的数据是否结束, 所以, 它根本就不知道最后3个是哪3个, 所以必须加上代码:

    [subject sendCompleted];
    
    

    运行结果:

    运行结果
        RACSubject *subject = [RACSubject subject];
       
        
        RACSubject *endSignal = [RACSubject subject];
        [[subject takeUntil:endSignal] subscribeNext:^(id  _Nullable x) {
            NSLog(@"endSignal发送信号后终止: %@ ", x);
        }];
        
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [endSignal sendNext:@"end"]; // [endSignal sendCompleted];也可以
        
        [subject sendNext:@"3"];
        [subject sendNext:@"4"];
        [subject sendNext:@"5"];
        [subject sendCompleted];
    

    以上代码表示, 当某一个信号发送数据的时候, 拿这个信号发送前的数据. 所以以上代码运行之后, 只能拿字符串1和2:

    运行结果

    4.distinctUntilChanged
    忽略重复数据:

        RACSubject *subject = [RACSubject subject];
        
        [[subject distinctUntilChanged] subscribeNext:^(id  _Nullable x) {
            NSLog(@"忽略掉重复的数据后得到的数据: %@ ", x);
        }];
        
        [subject sendNext:@"1"];
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [subject sendNext:@"2"];
        [subject sendNext:@"5"];
        [subject sendCompleted];
    

    运行结果:

    运行结果

    5.skip:
    跳过数据

        RACSubject *subject = [RACSubject subject];
        
        [[subject skip:3] subscribeNext:^(id  _Nullable x) {
            NSLog(@"跳过3个数据之后得到的数据: %@ ", x);
        }];
        
        [subject sendNext:@"1"];
        [subject sendNext:@"2"];
        [subject sendNext:@"3"];
        [subject sendNext:@"4"];
        [subject sendNext:@"5"];
        [subject sendCompleted];
    

    运行结果:

    运行结果

    以上!
    本文涉及到的代码下载 密码: ebrx

    相关文章

      网友评论

        本文标题:RAC常见用法(三)

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