美文网首页
iOS-ReactiveCocoa学习笔记

iOS-ReactiveCocoa学习笔记

作者: Simple_Code | 来源:发表于2018-07-05 15:47 被阅读50次

    关于ReactiveCocoa的比喻

    “能够把信号想象成水龙头,仅仅只是里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列。不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的。除非有了接收方(subscriber),才会打开。
    这样仅仅要有新的玻璃球进来,就会自己主动传送给接收方。
    能够在水龙头上加一个过滤嘴(filter)。不符合的不让通过,也能够加一个修改装置,把球改变成符合自己的需求(map)。
    也能够把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样仅仅要当中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。

    1.RACSignal

    #import <UIKit/UIKit.h>
    @interface RACSignalController : UIViewController
    @end
    
    #import "RACSignalController.h"
    @interface RACSignalController ()
    @property (nonatomic, strong) id<RACSubscriber> subscriber;
    @end
    
    @implementation RACSignalController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.navigationItem.title = @"RACSignal";
        
        /**
         1. RACSiganl:信号类,一般表示将来有数据传递,只要有数据改变,信号内部接收到数据,就会马上发出数据。
         信号类(RACSiganl),只是表示当数据改变时,信号内部会发出数据,它本身不具备发送信号的能力,而是交给内部一个订阅者去发出。
         
         2. 默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
         
         3. 如何订阅信号:调用信号RACSignal的subscribeNext就能订阅。
         */
        
        
        
        // 核心:信号类
        // 信号类作用:只要有数据改变,就会把数据包装成一个信号,传递出去。
        // 只要有数据改变,就会有信号发出。
        // 数据发出,并不是信号类发出。
        
        // 1.创建信号 createSignal:didSubscribe(block)
        // RACDisposable:取消订阅
        // RACSubscriber:发送数据
        
        // createSignal方法:
        // 1.创建RACDynamicSignal
        // 2.把didSubscribe保存到RACDynamicSignal
        
        RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            // block调用时刻:当信号被订阅的时候就会调用
            // block作用:描述当前信号哪些数据需要发送
            
            // 3.发送信号
            NSLog(@"调用了didSubscribe");
            // 通常:传递数据出去
            [subscriber sendNext:@"发送信号"];
            /**
             如果不在发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号
             */
            [subscriber sendCompleted];
            
            // 取消订阅方法
            return [RACDisposable disposableWithBlock:^{
                // 信号什么时候被取消:1.自动取消,当一个信号的订阅者被销毁的时候,就会自动取消订阅 2.主动取消
                // block调用时刻:一旦一个信号,被取消订阅的时候就会调用
                // block作用:当信号取消订阅,用于清空一些资源
                NSLog(@"信号销毁了");
            }];
        }];
        
        // 2.订阅信号
        [signal subscribeNext:^(id x) {
            NSLog(@"订阅信号:%@",x);
        }];
        
        //输出
        //订阅信号:发送信号
        //信号销毁了
    
        
        /**
         RACSignal底层实现
         1. 创建信号,首先把didSubscribe保存到信号中,还不会触发。
         2. 当信号被订阅,也就是调用signal的subscribeNext:nextBlock
         2.1 subscribeNext内部会调用siganl的didSubscribe
         2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中
         3.0 siganl的didSubscribe中调用[subscriber sendNext:@"发送信号"];
         3.1 sendNext底层其实就是执行subscriber的nextBlock
         */
        
        RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
           
            /**
             有一个全局变量保存值就不会走下面取消订阅方法:现在有问题
             */
            self.subscriber = subscriber;
            
            [subscriber sendNext:@"123"];
            [subscriber sendCompleted];
            
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"走销毁这个方法了");
            }];
        }];
        
        //订阅信号返回RACDisposable
        RACDisposable *disposable = [signal1 subscribeNext:^(id x) {
            NSLog(@"接收打印的值:%@",x);
        }];
        
        // 默认一个信号发送数据完毕们就会主动取消订阅.
        // 只要订阅者在,就不会自动取消信号订阅
        // 手动取消订阅者
        [disposable dispose];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    
    @end
    

    2.RACSubscriber

    #import <UIKit/UIKit.h>
    
    @interface RACSubscriberController : UIViewController
    
    @end
    
    #import "RACSubscriberController.h"
    #import "RedView.h"
    
    @interface RACSubscriberController ()
    
    @end
    
    @implementation RACSubscriberController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.navigationItem.title = @"RACSubscriber";
    
        /**
         1. RACSubscriber: 表示订阅者的意思,用于发送信号,这是一个协议,不是一个类,只要遵守这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助他发送数据。
         
         2. RACDisposable:用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。
         使用场景:不想监听某个信号时,可以通过它主动取消订阅信号。
         
         3. RACSubject:RACSubject:信号提供者,自己可以充当信号,又能发送信号。
         使用场景:通常用来代替代理,有了它,就不必要定义代理了。
         
         4. RACReplaySubject:重复提供信号类,RACSubject的子类。
         
         RACReplaySubject与RACSubject区别:
         RACReplaySubject可以先发送信号,在订阅信号,RACSubject就不可以。
         使用场景一:如果一个信号每被订阅一次,就需要把之前的值重复发送一遍,使用重复提供信号类。
         使用场景二:可以设置capacity数量来限制缓存的value的数量,即只缓充最新的几个值。
         
         */
        
        // RACSubject使用
        [self RACSubjectUse];
        
        // RACReplaySubject使用
        [self RACReplaySubjectUse];
        
        // RACSubject替换代理使用
        [self RACSubjectReplaceAgent];
        
    }
    #pragma mark - RACSubjectUse
    - (void)RACSubjectUse {
    
        // RACSubject使用步骤
        // 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
        // 2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 3.发送信号 sendNext:(id)value
        
        // 1.创建信号
        RACSubject *subject = [RACSubject subject];
        // 2.订阅信号
        [subject subscribeNext:^(id x) {
           //当信号发出新值,就会调用.
            NSLog(@"第一个订阅者%@",x);
        }];
        
        [subject subscribeNext:^(id x) {
            NSLog(@"第二个订阅者%@",x);
        }];
        
        // 3.发送信号
        [subject sendNext:@"123456"];
        // 4.发送信号完成,内部会自动取消订阅者
        [subject sendCompleted];
        
        // 输出:
        // 第一个订阅者123456
        // 第二个订阅者123456
    
        
    }
    #pragma mark - RACReplaySubjectUse
    -(void)RACReplaySubjectUse {
    
        // RACReplaySubject使用步骤:
        // 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
        // 2.可以先订阅信号,也可以先发送信号。
        // 2.1 订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
        // 2.2 发送信号 sendNext:(id)value
        
        // RACReplaySubject:底层实现和RACSubject不一样。
        // 1.调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
        // 2.调用subscribeNext订阅信号,遍历保存的所有值,一个一个调用订阅者的nextBlock
        
        // 1.创建信号
        RACReplaySubject *replaySubject = [RACReplaySubject subject];
        // 2.发送信号
        [replaySubject sendNext:@"1"];
        [replaySubject sendNext:@"2"];
        // 3.订阅信号
        [replaySubject subscribeNext:^(id x) {
            NSLog(@"第一个订阅者接收到的数据%@",x);
        }];
        
        [replaySubject subscribeNext:^(id x) {
    
            NSLog(@"第二个订阅者接收到的数据%@",x);
        }];
        
        // 输出:
        // 第一个订阅者接收到的数据1
        // 第一个订阅者接收到的数据2
        // 第二个订阅者接收到的数据1
        // 第二个订阅者接收到的数据2
    }
    
    #pragma mark - RACSubject替换代理
    - (void)RACSubjectReplaceAgent {
    
        RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
        redView.frame = CGRectMake(0, 64, 300, 200);
        redView.center = self.view.center;
        [redView.btnClickSignal subscribeNext:^(id x) {
            NSLog(@"---%@--",x);
        }];
        [self.view addSubview:redView];
    }
    @end
    

    3.RAC集合

    #import <UIKit/UIKit.h>
    
    @interface RACSetViewController : UIViewController
    
    @end
    
    #import "RACSetViewController.h"
    #import "Flag.h"
    
    @interface RACSetViewController ()
    
    @end
    
    @implementation RACSetViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self tuple];
        [self array];
        [self dictionary];
        [self initWithDictionary];
    }
    #pragma mark- RACTuple数组
    - (void)tuple {
       
        /**
         RACTuple:元组类,类似NSArray,用来包装值.
         */
        //元组
        RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"345",@1]];
        NSString *first = tuple[0];
        NSLog(@"%@",first);
        
        //输出:
        //123
    }
    #pragma mark- RACSequence数组
    - (void)array {
        // 数组
        NSArray *arr = @[@"213",@"321",@1];
        
        //RAC 集合
        RACSequence *sequence = arr.rac_sequence;
        // 把集合转换成信号
        RACSignal *signal = sequence.signal;
        //订阅集合信号,内部会自动遍历所有的元素发出来
        [signal subscribeNext:^(id x) {
            NSLog(@"遍历数组%@",x);
        }];
        
        
        //输出:
        /**
         遍历数组213
         遍历数组321
         遍历数组1
         */
        
        
        //高级写法
        [arr.rac_sequence.signal subscribeNext:^(id x) {
            NSLog(@"高级写法遍历数组打印%@",x);
        }];
        
        //输出:
        /**
         高级写法遍历数组打印213
         高级写法遍历数组打印321
         高级写法遍历数组打印1
         */
    }
    #pragma mark- RACTuple数组
    - (void)dictionary {
        // 字典
        NSDictionary *dict = @{@"sex":@"女",@"name":@"苍老师",@"age":@18};
        
        //转换成集合
        [dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
    //        NSString *key = x[0];
    //        NSString *value = x[1];
    //        NSLog(@"%@ %@",key,value);
            // RACTupleUnpack:用来解析元组
            // 宏里面的参数,传需要解析出来的变量名
            //= 右边,放需要解析的元组
            RACTupleUnpack(NSString *key, NSString *value) = x;
            NSLog(@"%@ %@",key,value);
         
        }];
        //输出:
        /**
         sex 女
         name 苍老师
         age 18
         */
    }
    
    #pragma mark- 字典转模型
    - (void)initWithDictionary {
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
        NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
        
        //    NSMutableArray *arr = [NSMutableArray array];
        //    // rac_sequence注意点:调用subscribeNext,并不会马上执行nextBlock,而是会等一会。
        
        //    [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
        //        Flag *flag = [Flag flagWithDict:x];
        //        [arr addObject:flag];
        //    }];
        
        //高级用法
        // map:映射的意思,目的:把原始值value映射成一个新值
        // array: 把集合转换成数组
        // 底层实现:当信号被订阅,会遍历集合中的原始值,映射成新值,并且保存到新的数组里。
        NSArray *arr = [[dictArr.rac_sequence map:^id(NSDictionary *value) {
            return [Flag flagWithDict:value];
        }] array];
        
        NSLog(@"%@",arr);
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    @end
    

    4.RACMulticastConnection

    #import <UIKit/UIKit.h>
    
    @interface RACMulticastConnectionController : UIViewController
    
    @end
    
    #import "RACMulticastConnectionController.h"
    
    @interface RACMulticastConnectionController ()
    
    @end
    
    @implementation RACMulticastConnectionController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        /**
         RACMulticastConnection:用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。
         使用注意:RACMulticastConnection通过RACSignal的-publish或者-muticast:方法创建.
         */
        
        
        [self RACMulticastConnection];
        
    }
    
    - (void)RACMulticastConnection {
        //RACMulticastConnection简单使用:
        // RACMulticastConnection使用步骤:
        // 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
        // 2.创建连接 RACMulticastConnection *connect = [signal publish];
        // 3.订阅信号,注意:订阅的不在是之前的信号,而是连接的信号。 [connect.signal subscribeNext:nextBlock]
        // 4.连接 [connect connect]
        
        // RACMulticastConnection底层原理:
        // 1.创建connect,connect.sourceSignal -> RACSignal(原始信号)  connect.signal -> RACSubject
        // 2.订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。
        // 3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者是RACSubject
        // 3.1.订阅原始信号,就会调用原始信号中的didSubscribe
        // 3.2 didSubscribe,拿到订阅者调用sendNext,其实是调用RACSubject的sendNext
        // 4.RACSubject的sendNext,会遍历RACSubject所有订阅者发送信号。
        // 4.1 因为刚刚第二步,都是在订阅RACSubject,因此会拿到第二步所有的订阅者,调用他们的nextBlock
        
        // 需求:假设在一个信号中发送请求,每次订阅一次都会发送请求,这样就会导致多次请求。
        // 解决:使用RACMulticastConnection就能解决.
        
        // 1.创建信号
        RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            NSLog(@"发送请求");
            
            [subscriber sendNext:@"1"];
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        // 2.订阅信号
        [signal subscribeNext:^(id x) {
           
            NSLog(@"接收数据");
        }];
        [signal subscribeNext:^(id x) {
            
            NSLog(@"接收数据");
        }];
        
        // 3.运行结果,会执行两遍发送请求,也就是每次订阅都会发送一次请求
        
        
        
        
        
        // RACMulticastConnection:解决重复请求问题
        // 1.创建信号
        RACSignal *connectionSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            NSLog(@"发送请求--");
            [subscriber sendNext:@1];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        //2.创建连接
        RACMulticastConnection *connect = [connectionSignal publish];
        
        //3.订阅信号
        // 注意:订阅信号,也不能激活信号,只是保存订阅者到数组,必须通过连接,当调用连接,就会一次性调用所有订阅者的sendNext:
        [connect.signal subscribeNext:^(id x) {
            NSLog(@"订阅者一信号--");
        }];
        [connect.signal subscribeNext:^(id x) {
            
            NSLog(@"订阅者二信号--");
            
        }];
        //4.连接,激活信号
        [connect connect];
        
        //输出:
        /**
         发送请求--
         订阅者一信号--
         订阅者二信号--
         */
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end
    

    5.RACCommand

    #import <UIKit/UIKit.h>
    
    @interface RACCommandController : UIViewController
    
    @end
    
    #import "RACCommandController.h"
    
    @interface RACCommandController ()
    @property (nonatomic, strong) RACCommand *command;
    @end
    
    @implementation RACCommandController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        /**
         RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。
         
         使用场景:监听按钮点击,网络请求
         */
        
        [self RACCommandUse];
        
        [self switchToLatest];
        
        [self commandData];
    }
    
    - (void)RACCommandUse {
    
        // 一、RACCommand使用步骤:
        // 1.创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
        // 2.在signalBlock中,创建RACSignal,并且作为signalBlock的返回值
        // 3.执行命令 - (RACSignal *)execute:(id)input
        
        // 二、RACCommand使用注意:
        // 1.signalBlock必须要返回一个信号,不能传nil.
        // 2.如果不想要传递信号,直接创建空的信号[RACSignal empty];
        // 3.RACCommand中信号如果数据传递完,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中。
        // 三、RACCommand设计思想:内部signalBlock为什么要返回一个信号,这个信号有什么用。
        // 1.在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。
        // 2.当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了。
        
        // 四、如何拿到RACCommand中返回信号发出的数据。
        // 1.RACCommand有个执行信号源executionSignals,这个是signal of signals(信号的信号),意思是信号发出的数据是信号,不是普通的类型。
        // 2.订阅executionSignals就能拿到RACCommand中返回的信号,然后订阅signalBlock返回的信号,就能获取发出的值。
        
        // 五、监听当前命令是否正在执行executing
        
        // 六、使用场景,监听按钮点击,网络请求
        
        // 1.创建命令
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
           
            NSLog(@"执行命令");
            // 创建空信号,必须返回信号
            // return [RACSignal empty];
            
            // 2.创建信号,用来传递数据
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
               
                [subscriber sendNext:@"请求数据"];
                
                // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
                [subscriber sendCompleted];
                
                return [RACDisposable disposableWithBlock:^{
                    NSLog(@"数据销毁");
                }];
            }];
        }];
        
        // 强引用命令,不要被销毁,否则接收不到数据
        _command = command;
        
        // 监听事件有没有完成
        [command.executing subscribeNext:^(id x) {
            
            if ([x boolValue] == YES) { // 当前正在执行
                
                NSLog(@"当前正在执行");
            }else{
                
                // 执行完成/没有执行
                NSLog(@"执行完成/没有执行");
            }
        }];
        
        // 获取信号中信号发送的最新信号
        [self.command.executionSignals.switchToLatest subscribeNext:^(id x) {
            NSLog(@"%@",x);
        }];
        
        // 执行命令
        //[self.command execute:@1];
    }
    
    
    // RAC高级用法
    - (void)switchToLatest {
    
        //创建信号中信号
        RACSubject *signalOfSignals = [RACSubject subject];
        RACSubject *signalA = [RACSubject subject];
        RACSubject *signalB = [RACSubject subject];
        // 订阅信号
    //        [signalOfSignals subscribeNext:^(RACSignal *x) {
    //            [x subscribeNext:^(id x) {
    //                NSLog(@"%@",x);
    //            }];
    //        }];
    //     switchToLatest:获取信号中信号发送的最新信号
        [signalOfSignals.switchToLatest subscribeNext:^(id x) {
            
            NSLog(@"%@",x);
        }];
        
        // 发送信号
        [signalOfSignals sendNext:signalA];
        
        [signalA sendNext:@1];
        [signalB sendNext:@"BB"];
        [signalA sendNext:@"11"];
    }
    - (void)commandData
    {
        // RACCommand:处理事件
        // RACCommand:不能返回一个空的信号
        // 1.创建命令
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            // input:执行命令传入参数
            // Block调用:执行命令的时候就会调用
            NSLog(@"input-%@",input);
            
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                
                // 发送数据
                [subscriber sendNext:@"执行命令产生的数据"];
                
                return nil;
            }];
        }];
        
        // 如何拿到执行命令中产生的数据
        // 订阅命令内部的信号
        // 1.方式一:直接订阅执行命令返回的信号
        // 2.方式二:
        
        // 2.执行命令
        RACSignal *signal = [command execute:@1];
        
        // 3.订阅信号
        [signal subscribeNext:^(id x) {
            NSLog(@"x-%@",x);
        }];
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    
    @end
    

    6.RAC常用方法--常见宏

    @interface RACMethodUseViewController : UIViewController
    
    @end
    
    #import "RACMethodUseViewController.h"
    #import "RedView.h"
    
    @interface RACMethodUseViewController ()
    
    @end
    
    @implementation RACMethodUseViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        #pragma mark -常见的五个宏
        ////常见的五个宏
        //使用宏定义要单独导入 #import <RACEXTScope.h>
    
        // 1:
        /*
         RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定信号
         只要文本框文字改变,就会修改label的文字
         RAC(self.labelView,text) = _textField.rac_textSignal;
         */
        
        // 2:
        /*
        RACObserve(self, name):监听某个对象的某个属性,返回的是信号。
        [RACObserve(self.view, center) subscribeNext:^(id x) {
            NSLog(@"%@",x);
        }];
        */
        
        
        //当RACObserve放在block里面使用时一定要加上weakify,不管里面有没有使用到self;否则会内存泄漏,因为RACObserve宏里面就有一个self
        /*
        @weakify(self);
        RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) {
         Avoids a retain cycle because of RACObserve implicitly referencing self
            @strongify(self);
            return RACObserve(arrayController, items);
        }];
         */
        
        //3:
        //@weakify(Obj)和@strongify(Obj),一般两个都是配套使用,在主头文件(ReactiveCocoa.h)中并没有导入,需要自己手动导入,RACEXTScope.h才可以使用。但是每次导入都非常麻烦,只需要在主头文件自己导入就好了
        
        // 4:
        /*
        RACTuplePack:把数据包装成RACTuple(元组类)
        把参数中的数据包装成元组
        RACTuple *tuple = RACTuplePack(@10,@20);
         */
        
        //5:
        /*
        RACTupleUnpack:把RACTuple(元组类)解包成对应的数据
        把参数中的数据包装成元组
        RACTuple *tuple = RACTuplePack(@"xmg",@20);
        
        解包元组,会把元组的值,按顺序给参数里面的变量赋值
        name = @"xmg" age = @20
        RACTupleUnpack(NSString *name,NSNumber *age) = tuple;
        */
        
        
        [self initView];
    }
    
    - (void)initView {
    
        self.navigationItem.title = @"RAC常用方法";
        self.view.backgroundColor = [UIColor whiteColor];
        
    #pragma mark -监听按钮的点击事件
        // 1.监听按钮的点击事件
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(100, 100, 80, 40);
        [button setTitle:@"点击事件" forState:UIControlStateNormal];
        [button setBackgroundColor:[UIColor redColor]];
        [self.view addSubview:button];
        [[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
            NSLog(@"按钮被点击了");
        }];
    
    #pragma mark -代理的使用
        // 2.代理的使用
        // 2.1 只要传值,就必须使用RACSubject
        RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
        redView.frame = CGRectMake(0, 140, self.view.bounds.size.width, 200);
        [self.view addSubview:redView];
        [redView.btnClickSignal subscribeNext:^(id x) {
            NSLog(@"---点击按钮了,触发了事件");
        }];
        
        // 2.2把控制器调用didReceiveMemoryWarning转换成信号
        // rac_signalForSelector:监听某对象有没有调用某方法
        [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
            NSLog(@"控制器调用didReceiveMemoryWarning");
        }];
        
    #pragma mark -KVO
        // 3.KVO
        // 把监听redV的center属性改变转换成信号,只要值改变就会发送信号
        // observer:可以传入nil
        [[redView rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
            NSLog(@"center:%@",x);
        }];
        
    #pragma mark -代替通知
        // 4.代替通知
        UITextField *textfield = [[UITextField alloc] initWithFrame:CGRectMake(100, 340, 150, 40)];
        textfield.placeholder = @"监听键盘的弹起";
        textfield.borderStyle = UITextBorderStyleRoundedRect;
        [self.view addSubview:textfield];
        
        
        [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
            NSLog(@"监听键盘的高度:%@",x);
        }];
        
    #pragma mark -监听文本框的文字改变
        // 5.监听文本框的文字改变
        [textfield.rac_textSignal subscribeNext:^(id x) {
            NSLog(@"输入框中文字改变了---%@",x);
        }];
        
    #pragma mark -处理多个请求,都返回结果的时候,统一做处理.
        // 6.处理多个请求,都返回结果的时候,统一做处理.
        RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            // 发送请求1
            [subscriber sendNext:@"发送请求1"];
            return nil;
        }];
        
        RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            // 发送请求2
            [subscriber sendNext:@"发送请求2"];
            return nil;
        }];
        
        // 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
        [self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
    }
    
    // 更新UI
    - (void)updateUIWithR1:(id)data r2:(id)data1
    {
        NSLog(@"更新UI%@  %@",data,data1);
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    @end
    
    

    7.RAC操作方法一

    #import <UIKit/UIKit.h>
    
    @interface RACOperationMethodController : UIViewController
    
    @end
    //1.ReactiveCocoa常见操作方法介绍。
    
    /**
     1.1 ReactiveCocoa操作须知
     
     所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中,而RACSignal继承RACStream。
     1.2 ReactiveCocoa操作思想
     
     运用的是Hook(钩子)思想,Hook是一种用于改变API(应用程序编程接口:方法)执行结果的技术.
     Hook用处:截获API调用的技术。
     Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出。
     RAC开发方式:RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。
     列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。
     1.3 ReactiveCocoa核心方法bind
     
     ReactiveCocoa操作的核心方法是bind(绑定),给RAC中的信号进行绑定,只要信号一发送数据,就能监听到,从而把发送数据改成自己想要的数据。
     
     在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.
     
     bind方法简单介绍和使用。
     */
    
    /**
     // 假设想监听文本框的内容,并且在每次输出结果的时候,都在文本框的内容拼接一段文字“输出:”
     
     // 方式一:在返回结果后,拼接。
     [_textField.rac_textSignal subscribeNext:^(id x) {
     
     NSLog(@"输出:%@",x);
     
     }];
     
     // 方式二:在返回结果前,拼接,使用RAC中bind方法做处理。
     // bind方法参数:需要传入一个返回值是RACStreamBindBlock的block参数
     // RACStreamBindBlock是一个block的类型,返回值是信号,参数(value,stop),因此参数的block返回值也是一个block。
     
     // RACStreamBindBlock:
     // 参数一(value):表示接收到信号的原始值,还没做处理
     // 参数二(*stop):用来控制绑定Block,如果*stop = yes,那么就会结束绑定。
     // 返回值:信号,做好处理,在通过这个信号返回出去,一般使用RACReturnSignal,需要手动导入头文件RACReturnSignal.h。
     
     // bind方法使用步骤:
     // 1.传入一个返回值RACStreamBindBlock的block。
     // 2.描述一个RACStreamBindBlock类型的bindBlock作为block的返回值。
     // 3.描述一个返回结果的信号,作为bindBlock的返回值。
     // 注意:在bindBlock中做信号结果的处理。
     
     // 底层实现:
     // 1.源信号调用bind,会重新创建一个绑定信号。
     // 2.当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock。
     // 3.当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
     // 4.调用bindingBlock(value,stop),会返回一个内容处理完成的信号(RACReturnSignal)。
     // 5.订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
     
     // 注意:不同订阅者,保存不同的nextBlock,看源码的时候,一定要看清楚订阅者是哪个。
     // 这里需要手动导入#import <ReactiveCocoa/RACReturnSignal.h>,才能使用RACReturnSignal。
     
     [[_textField.rac_textSignal bind:^RACStreamBindBlock{
     
     // 什么时候调用:
     // block作用:表示绑定了一个信号.
     
     return ^RACStream *(id value, BOOL *stop){
     
     // 什么时候调用block:当信号有新的值发出,就会来到这个block。
     
     // block作用:做返回值的处理
     
     // 做好处理,通过信号返回出去.
     return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
     };
     
     }] subscribeNext:^(id x) {
     
     NSLog(@"%@",x);
     
     }];
     */
    
    #import "RACOperationMethodController.h"
    #import <RACReturnSignal.h>
    @interface RACOperationMethodController ()
    @property (strong, nonatomic) UITextField *textField;
    
    @end
    
    @implementation RACOperationMethodController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self initView];
        [self flattenMap];
        [self map];
        [self flatternMapWithMap];
        [self RACOperationMethodCombination];
    }
    
    - (void)initView {
        self.navigationItem.title = @"RAC 操作方法一";
        self.view.backgroundColor = [UIColor whiteColor];
        
        _textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
        _textField.center = self.view.center;
        _textField.placeholder = @"请输入内容";
        [self.view addSubview:_textField];
    }
    
    //flattenMap简单使用
    // 监听文本框的内容改变,把结构重新映射成一个新值.
    // flattenMap作用:把源信号的内容映射成一个新的信号,信号可以是任意类型。
    - (void)flattenMap {
        
        // flattenMap使用步骤:
        // 1.传入一个block,block类型是返回值RACStream,参数value
        // 2.参数value就是源信号的内容,拿到源信号的内容做处理
        // 3.包装成RACReturnSignal信号,返回出去。
        
        // flattenMap底层实现:
        // 0.flattenMap内部调用bind方法实现的,flattenMap中block的返回值,会作为bind中bindBlock的返回值。
        // 1.当订阅绑定信号,就会生成bindBlock。
        // 2.当源信号发送内容,就会调用bindBlock(value, *stop)
        // 3.调用bindBlock,内部就会调用flattenMap的block,flattenMap的block作用:就是把处理好的数据包装成信号。
        // 4.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
        // 5.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
    
        [[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
            // block什么时候 : 源信号发出的时候,就会调用这个block。
            
            // block作用 : 改变源信号的内容。
            // 返回值:绑定信号的内容.
            return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
        }] subscribeNext:^(id x) {
             // 订阅绑定信号,每当源信号发送内容,做完处理,就会调用这个block。
            NSLog(@"输出:flattenMap%@",x);
        }];
    }
    
    - (void)map {
    
        //Map简单使用:
        // 监听文本框的内容改变,把结构重新映射成一个新值.
        // Map作用:把源信号的值映射成一个新的值
        
        // Map使用步骤:
        // 1.传入一个block,类型是返回对象,参数是value
        // 2.value就是源信号的内容,直接拿到源信号的内容做处理
        // 3.把处理好的内容,直接返回就好了,不用包装成信号,返回的值,就是映射的值。
        
        // Map底层实现:
        // 0.Map底层其实是调用flatternMap,Map中block中的返回的值会作为flatternMap中block中的值。
        // 1.当订阅绑定信号,就会生成bindBlock。
        // 3.当源信号发送内容,就会调用bindBlock(value, *stop)
        // 4.调用bindBlock,内部就会调用flattenMap的block
        // 5.flattenMap的block内部会调用Map中的block,把Map中的block返回的内容包装成返回的信号。
        // 5.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
        // 6.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
        
        [[_textField.rac_textSignal map:^id(id value) {
            // 当源信号发出,就会调用这个block,修改源信号的内容
            // 返回值:就是处理完源信号的内容。
            return [NSString stringWithFormat:@"输出:%@",value];
        }] subscribeNext:^(id x) {
            
            NSLog(@"map输出%@",x);
        }];
    }
    
    - (void)flatternMapWithMap {
    
        /**
         FlatternMap和Map的区别
         
         1.FlatternMap中的Block返回信号。
         2.Map中的Block返回对象。
         3.开发中,如果信号发出的值不是信号,映射一般使用Map
         4.开发中,如果信号发出的值是信号,映射一般使用FlatternMap。
         总结:signalOfsignals用FlatternMap。
         */
        
        //创建信号中的信号
        RACSubject *signalOfsignals = [RACSubject subject];
        RACSubject *signal = [RACSubject subject];
        
        [[signalOfsignals flattenMap:^RACStream *(id value) {
           
            //当signalOfsignals的signals发出信号才会调用
            return value;
        }] subscribeNext:^(id x) {
            // 只有signalOfsignals的signal发出信号才会调用,因为内部订阅了bindBlock中返回的信号,也就是flattenMap返回的信号。
            // 也就是flattenMap返回的信号发出内容,才会调用。
            
            NSLog(@"%@aaa",x);
        }];
        
        // 信号的信号发送信号
        [signalOfsignals sendNext:signal];
        
        // 信号发送内容
        [signal sendNext:@1];
    }
    
    //RAC 操作之组合
    - (void)RACOperationMethodCombination {
    
        //一.concat:按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。
        RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@1];
            [subscriber sendCompleted];
            return nil;
        }];
        
        RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@2];
            [subscriber sendCompleted];
            
            return nil;
        }];
        
        // 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。
        RACSignal *concatSignal = [signalA concat:signalB];
        
        // 以后只需要面对拼接信号开发。
        // 订阅拼接的信号,不需要单独订阅signalA,signalB
        // 内部会自动订阅。
        // 注意:第一个信号必须发送完成,第二个信号才会被激活
        [concatSignal subscribeNext:^(id x) {
            
            NSLog(@"%@",x);
        }];
        
        // concat底层实现:
        // 1.当拼接信号被订阅,就会调用拼接信号的didSubscribe
        // 2.didSubscribe中,会先订阅第一个源信号(signalA)
        // 3.会执行第一个源信号(signalA)的didSubscribe
        // 4.第一个源信号(signalA)didSubscribe中发送值,就会调用第一个源信号(signalA)订阅者的nextBlock,通过拼接信号的订阅者把值发送出来.
        // 5.第一个源信号(signalA)didSubscribe中发送完成,就会调用第一个源信号(signalA)订阅者的completedBlock,订阅第二个源信号(signalB)这时候才激活(signalB)。
        // 6.订阅第二个源信号(signalB),执行第二个源信号(signalB)的didSubscribe
        // 7.第二个源信号(signalA)didSubscribe中发送值,就会通过拼接信号的订阅者把值发送出来.
        
        //二.then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号。
        // then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号
        // 注意使用then,之前信号的值会被忽略掉.
        // 底层实现:1、先过滤掉之前的信号发出的值。2.使用concat连接then返回的信号
        
        [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            [subscriber sendNext:@1];
            [subscriber sendCompleted];
            
            return nil;
            
        }] then:^RACSignal *{
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                [subscriber sendNext:@2];
                return nil;
            }];
        }] subscribeNext:^(id x) {
            // 只能接收到第二个信号的值,也就是then返回信号的值
            NSLog(@"%@",x);
        }];
        
        
        //三.merge:把多个信号合并为一个信号,任何一个信号有新值的时候就会调用.
        //merge: 把多个信号合并成一个信号
        //创建多个信号
        
        RACSignal *signalC = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            [subscriber sendNext:@3];
            
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"信号释放了");
            }];
        }];
        
        RACSignal *signalD = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@4];
            
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"信号释放了");
            }];
        }];
        
        //合并信号.任何一个信号发送数据,都能监听到
        
        RACSignal *mergeSignal = [signalC merge:signalD];
        [mergeSignal subscribeNext:^(id x) {
            NSLog(@"合并信号,任何一个数据发送数据,都能监听到%@",x);
        }];
        
        // 底层实现:
        // 1.合并信号被订阅的时候,就会遍历所有信号,并且发出这些信号。
        // 2.每发出一个信号,这个信号就会被订阅
        // 3.也就是合并信号一被订阅,就会订阅里面所有的信号。
        // 4.只要有一个信号被发出就会被监听。
        
        //四.zipWith:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。
        
        RACSignal *signalE = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@5];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        RACSignal *signalF = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@6];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        // 压缩信号A,信号B
        
        RACSignal *zipSignal = [signalE zipWith:signalF];
        
        [zipSignal subscribeNext:^(id x) {
            NSLog(@"压缩的信号%@",x);
        }];
        
        // 底层实现:
        // 1.定义压缩信号,内部就会自动订阅signalA,signalB
        // 2.每当signalA或者signalB发出信号,就会判断signalA,signalB有没有发出个信号,有就会把最近发出的信号都包装成元组发出。
        
        
        //第五:combineLatest:将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号.
        
        RACSignal *signalG = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@5];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        RACSignal *signalH = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@6];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        // 把两个信号组合成一个信号,跟zip一样,没什么区别
        RACSignal *combineSignal = [signalG combineLatestWith:signalH];
        
        [combineSignal subscribeNext:^(id x) {
           NSLog(@"把两个信号组合成一个信号%@",x);
        }];
        
        // 底层实现:
        // 1.当组合信号被订阅,内部会自动订阅signalA,signalB,必须两个信号都发出内容,才会被触发。
        // 2.并且把两个信号组合成元组发出。
        
        
        //第六:reduce聚合:用于信号发出的内容是元组,把信号发出元组的值聚合成一个值
        RACSignal *signalL = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@5];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        RACSignal *signalM = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@6];
            
            return [RACDisposable disposableWithBlock:^{
                
            }];
        }];
        
        RACSignal *reduceSignal = [RACSignal combineLatest:@[signalL,signalM] reduce:^id(NSNumber *num1, NSNumber *num2){
            return [NSString stringWithFormat:@"reduce聚合%@ %@",num1,num2];
        }];
        
        [reduceSignal subscribeNext:^(id x) {
            NSLog(@"%@",x);
     
        }];
        
        // // 底层实现:
        // 1.订阅聚合信号,每次有内容发出,就会执行reduceblcok,把信号内容转换成reduceblcok返回的值。
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        [self.view endEditing:YES];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    8.RAC操作方法二

    #import <UIKit/UIKit.h>
    
    @interface RACOperationMethodFilteringVC : UIViewController
    
    @end
    
    #import "RACOperationMethodFilteringVC.h"
    
    @interface RACOperationMethodFilteringVC ()
    @property (strong, nonatomic) UITextField *textField;
    
    @end
    
    @implementation RACOperationMethodFilteringVC
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self initView];
        [self filter];
        [self ignore];
        [self ignoreValues];
        [self takeUntilBlock];
        [self distinctUntilChanged];
        [self take];
        [self takeLast];
        [self takeUntil];
        [self skip];
        [self switchToLatest];
    }
    
    - (void)initView {
    
        self.navigationItem.title = @"RAC操作方法二";
        self.view.backgroundColor = [UIColor whiteColor];
        
        _textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
        _textField.center = self.view.center;
        _textField.borderStyle = UITextBorderStyleBezel;
        _textField.placeholder = @"请输入内容";
        [self.view addSubview:_textField];
    }
    
    //过滤信号,使用它可以获取满足条件的信号.
    - (void)filter {
    
        //filter 过滤
        //每次信号发出,会先执行过滤条件判断
        [_textField.rac_textSignal filter:^BOOL(NSString *value) {
           
            return value.length > 3;
        }];
    }
    
    //ignore:忽略完某些值的信号.
    - (void)ignore {
        // 内部调用filter过滤,忽略掉ignore的值
        [[_textField.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {
            NSLog(@"ignore%@",x);
        }];
        
    }
    
    //ignoreValues 这个比较极端,忽略所有值,只关心Signal结束,也就是只取Comletion和Error两个消息,中间所有值都丢弃
    - (void)ignoreValues {
        
        RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"1"];
            [subscriber sendNext:@"3"];
            [subscriber sendNext:@"15"];
            [subscriber sendNext:@"wujy"];
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"执行清理");
            }];
        }];
        
        
        [[signal ignoreValues] subscribeNext:^(id x) {
            //它是没机会执行  因为ignoreValues已经忽略所有的next值
            NSLog(@"ignoreValues当前值:%@",x);
        } error:^(NSError *error) {
            NSLog(@"ignoreValues error");
        } completed:^{
            NSLog(@"ignoreValues completed");
        }];
        
    }
    
    
    //distinctUntilChanged:当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。
    - (void)distinctUntilChanged {
    
        // 过滤,当上一次和当前的值不一样,就会发出内容。
        // 在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
        
        [[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
            NSLog(@"distinctUntilChanged%@",x);
        }];
    }
    
    //take:从开始一共取N次的信号
    - (void)take {
    
        //1.创建信号
        RACSubject *signal = [RACSubject subject];
        //2.处理信号,订阅信号
        [[signal take:1] subscribeNext:^(id x) {
            NSLog(@"take:%@",x);
    
        }];
        
        // 3.发送信号
        [signal sendNext:@1];
        
        [signal sendNext:@2];
    }
    
    //takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号.
    - (void)takeLast {
    
        //1.创建信号
        RACSubject *signal = [RACSubject subject];
        //2.处理信号,订阅信号
        [[signal takeLast:2] subscribeNext:^(id x) {
            NSLog(@"%@",x);
    
        }];
        
        //3.发送信号
        [signal sendNext:@1];
        [signal sendNext:@332];
        [signal sendNext:@333];
        [signal sendCompleted];
    }
    
    //takeUntil:(RACSignal *):获取信号直到执行完这个信号
    - (void)takeUntil {
        // 监听文本框的改变,知道当前对象被销毁
        [_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
    }
    
    //takeUntilBlock 对于每个next值,运行block,当block返回YES时停止取值
    - (void)takeUntilBlock {
        
        RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"1"];
            [subscriber sendNext:@"3"];
            [subscriber sendNext:@"15"];
            [subscriber sendNext:@"wujy"];
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"执行清理");
            }];
        }];
        
        [[signal takeUntilBlock:^BOOL(NSString *x) {
            if ([x isEqualToString:@"15"]) {
                return YES;
            }
            return NO;
        }] subscribeNext:^(id x) {
            NSLog(@"takeUntilBlock 获取的值:%@",x);
        }];
        
        //    输出
        //    takeUntilBlock 获取的值:1
        //    takeUntilBlock 获取的值:3
    }
    
    
    //skip:(NSUInteger):跳过几个信号,不接受。
    - (void)skip {
    
        [[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {
            NSLog(@"跳过几个信号不接收%@",x);
        }];
    }
    
    //switchToLatest:用于signalOfSignals(信号的信号),有时候信号也会发出信号,会在signalOfSignals中,获取signalOfSignals发送的最新信号。
    - (void)switchToLatest {
        RACSubject *signalOfSignals = [RACSubject subject];
        RACSubject *signal = [RACSubject subject];
        [signalOfSignals sendNext:signal];
        // 获取信号中信号最近发出信号,订阅最近发出的信号。
        // 注意switchToLatest:只能用于信号中的信号
        
        [signalOfSignals.switchToLatest subscribeNext:^(id x) {
            
            NSLog(@"获取信号中信号最近发出信号,订阅最近发出的信号%@",x);
        }];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
        [self.view endEditing:YES];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    9.RAC操作方法三

    #import <UIKit/UIKit.h>
    
    @interface RACOperationOrderController : UIViewController
    
    @end
    
    #import "RACOperationOrderController.h"
    
    @interface RACOperationOrderController ()
    @property (nonatomic, strong) RACSubject *signal;
    @end
    
    @implementation RACOperationOrderController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self initView];
        
        [self doNext];
        
        [self deliverOn];
        
        [self timeout];
        
        [self interval];
        
        [self delay];
        
        [self retry];
        
        [self replay];
        
        [self throttle];
    }
    
    - (void)initView {
        self.navigationItem.title = @"RAC操作方法三";
        self.view.backgroundColor = [UIColor whiteColor];
    }
    
    //ReactiveCocoa操作方法之秩序。
    - (void)doNext {
    
        //doNext: 执行Next之前,会先执行这个Block
        //doCompleted: 执行sendCompleted之前,会先执行这个Block
        [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@1];
            [subscriber sendCompleted];
            return nil;
        }] doNext:^(id x) {
            // 执行[subscriber sendNext:@1];之前会调用这个Block
            NSLog(@"doNext");
        }] doCompleted:^{
            // 执行[subscriber sendCompleted];之前会调用这个Block
            NSLog(@"doCompleted");
        }] subscribeNext:^(id x) {
            NSLog(@"%@",x);
    
        }];
    }
    
    //ReactiveCocoa操作方法之线程。
    - (void)deliverOn {
        //deliverOn: 内容传递切换到制定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
        
        //subscribeOn: 内容传递和副作用都会切换到制定线程中。
    }
    
    //ReactiveCocoa操作方法之时间。
    - (void)timeout {
        //timeout:超时,可以让一个信号在一定的时间后,自动报错。
        RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            return nil;
        }] timeout:1 onScheduler:[RACScheduler currentScheduler]];
        
        [signal subscribeNext:^(id x) {
            
            NSLog(@"%@",x);
    
        } error:^(NSError *error) {
            // 1秒后会自动调用
            NSLog(@"%@",error);
        }];
    }
    
    //interval 定时:每隔一段时间发出信号
    - (void)interval {
    
        [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
            NSLog(@"%@",x);
        } error:^(NSError *error) {
             NSLog(@"%@",error);
        }];
    }
    
    //delay 延迟发送next
    - (void)delay {
    
       [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
          
            [subscriber sendNext:@1];
            return nil;
        }] delay:2] subscribeNext:^(id x) {
             NSLog(@"%@",x);
        }];
    }
    
    // ReactiveCocoa操作方法之重复。
    - (void)retry {
        //retry重试 :只要失败,就会重新执行创建信号中的block,直到成功.
        __block int i = 0;
        [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            if (i == 10) {
                [subscriber sendNext:@1];
            }else{
                NSLog(@"接收到错误");
                [subscriber sendError:nil];
            }
            i++;
            return nil;
            
        }] retry] subscribeNext:^(id x) {
            
            NSLog(@"%@",x);
            
        } error:^(NSError *error) {
            
            
        }];
    }
    
    //replay重放:当一个信号被多次订阅,反复播放内容
    - (void)replay {
        RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            
            [subscriber sendNext:@1];
            [subscriber sendNext:@2];
            
            return nil;
        }] replay];
        
        [signal subscribeNext:^(id x) {
            
            NSLog(@"第一个订阅者%@",x);
            
        }];
        
        [signal subscribeNext:^(id x) {
            
            NSLog(@"第二个订阅者%@",x);
            
        }];
    }
    
    
    - (void)throttle {
        RACSubject *signal = [RACSubject subject];
        _signal = signal;
        // 节流,在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。
        [[signal throttle:1] subscribeNext:^(id x) {
            NSLog(@"%@",x);
        }];
    }
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    
    @end
    

    相关文章

      网友评论

          本文标题:iOS-ReactiveCocoa学习笔记

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