美文网首页iOS 学习笔记
ReactiveCocoa 初识(一)

ReactiveCocoa 初识(一)

作者: Misaki_yuyi | 来源:发表于2018-06-21 11:31 被阅读70次

        入职有一段时间了,没有开发任务,白天就看看博客写写自己的东西,晚上看世界杯,简直不要太爽,就是天台有点挤了(╯3╰)。
        最近在学习ReactiveCocoa,项目导入ReactiveObjC开干。

    RACSignal
        RACSignal是RAC核心的类,使用的时候先创建信号,订阅信号,在创建信号的block里面发送信号。

    - (void)RACSignal
    {
        //1 创建信号
        RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            //3 发送信号
            [subscriber sendNext:@"发送信号"];
            
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"取消订阅");
            }];
    //        return nil;
        }];
        
        //2 订阅信号
        RACDisposable * disposable = [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //4 取消订阅
        [disposable dispose];
    }
    

    RACSubject
        RACSubject是继承自RACSignal,同时也遵循RACSubscriber协议。所以RACSubject既可以订阅信号,也能发送信号。使用方法也是先订阅后发送。它和RACReplaySubject的区别是,RACReplaySubject可以先发送后订阅。

    - (void)RACSubject
    {    
        //1 创建信号
        RACSubject * subject = [RACSubject subject];
        
        //2 订阅信号
        [subject subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //3 发送信号
        [subject sendNext:@"发送信号"];
    }
    

    RACSequence
        RACSequence一般用于遍历数组和字典等容器类,RAC扩展了一种数据类型Tuple元祖,接触过Swift的一定不会陌生。

    - (void)RACSequence
    {
        //遍历
        
        NSArray * array = @[@"1",@"2",@"3",@"3",@"5"];
        [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //元祖
        RACTuple * tuple = RACTuplePack(array);
        NSLog(@"%@",tuple[0]);
        NSLog(@"%@",[tuple first]);
        NSLog(@"%@",[tuple last]);
        
        NSDictionary * dict = @{@"key1":@"value1",@"key2":@"value2"};
        [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
            RACTupleUnpack(NSString * key,NSString * value) = x;
            NSLog(@"%@  %@",key,value);
        }];
        
        //替换数组的元素 生成新的数组 单个操作
        NSArray * newArray1 = [[array.rac_sequence map:^id _Nullable(id  _Nullable value) {
            return @"0";
        }] array];
        NSLog(@"%@",newArray1);
        
        //替换数组的元素 生成新的数组 全部操作
        NSArray * newArray2 = [[array.rac_sequence mapReplace:@"1"] array];
        NSLog(@"%@",newArray2);
    }
    

    RACMulticastConnection
        ReactiveCocoa中信号默认都是冷的,每次有新的订阅者订阅信号的时候都会执行信号创建时传入的block。举个例子,把一个网络请求的结果设置为信号,多个UI订阅了这个信号,每次订阅的时候,都会进行一次网络请求。

    RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            /*网络请求*/
            [subscriber sendNext:@"发送信号"];
            return nil;
        }];
        
        [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
    

        为了避免这一情况,使用RACMulticastConnection,创建链接类,将订阅者连接起来,把信号源变成热信号。

    - (void)RACMulticastConnection
    {
        //多个订阅者 只发一个信号
        RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@"发送信号"];
            return nil;
        }];
        
        //创建链接类
        RACMulticastConnection * connection = [signal publish];
        
        [connection.signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        [connection.signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        [connection.signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //连接 把信号源变为热信号
        [connection connect];
    }
    

    merge
        信号的合并

    - (void)merge
    {
        RACSubject * subject1 = [RACSubject subject];
        RACSubject * subject2 = [RACSubject subject];
        RACSubject * subject3 = [RACSubject subject];
        
        [[RACSignal merge:@[subject1,subject2,subject3]] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        [subject1 sendNext:@"subject1"];
        [subject2 sendNext:@"subject2"];
        [subject3 sendNext:@"subject3"];
    }
    

    group
        类似于GCD的任务组,完成多个任务后才能执行某个方法

    - (void)group
    {
        RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            /*网络请求1*/
            [subscriber sendNext:@"请求1完成"];
            return nil;
        }];
        
        RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            /*网络请求2*/
            [subscriber sendNext:@"请求2完成"];
            return nil;
        }];
        
        [self rac_liftSelector:@selector(dependSignalA:WithSignalB:) withSignalsFromArray:@[signalA,signalB]];
    }
    
    - (void)dependSignalA:(NSString *)str1 WithSignalB:(NSString *)str2
    {
        
    }
    

    Notification && KVO
        RAC来替换Notification和KVO的

    - (void)Notification
    {
        //不用写removeObserver
        [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"NotificationName" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
            NSLog(@"%@",x);
        }];
    }
    
    - (void)KVO
    {
        [[self.view rac_valuesForKeyPath:@"color" observer:self] subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
    }
    

    Timer
        RAC实现一个Timer的功能

    - (void)Timer
    {
        RACDisposable * disposable = [[RACSignal interval:1.f onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
            //当前时间
            NSLog(@"%@",x);
            
            [disposable dispose];
        }];
    }
    

    UI
        再来看看RAC在UI上的一些应用

    - (void)UI
    {
        UITextField * tf = [UITextField new];
        UITextField * tf2 = [UITextField new];
        UIButton * btn = [UIButton new];
        
        [[tf rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //filter 和 ignore
        [[[tf2.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
            return value.length > 6;
        }] ignore:@"666"] subscribeNext:^(NSString * _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //响应事件
        [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //两个输入框长度大于3的时候 按钮才可以点击
        RAC(btn,enabled) = [RACSignal combineLatest:@[tf.rac_textSignal,tf2.rac_textSignal] reduce:^id (NSString * str1, NSString * str2){
            return @(str1.length > 3 && str2.length > 3);
        }];
    }
    

        ReactiveCocoa是个响应式编程框架,在iOS中没有接触过类似的代码。不过之前有接触过AngularJS,对里面ng-Model指令,单向绑定、双向绑定有一定的了解。下篇会重点理解RACCommand,结合一个登录的Demo来实践。
        代码: ReactiveObjCDemo

    相关文章

      网友评论

        本文标题:ReactiveCocoa 初识(一)

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