ReactiveCocoa学习笔记

首先pod的集成

OC的集成版本为

pod 'ReactiveCocoa', :git => 'https://github.com/zhao0/ReactiveCocoa.git', :tag => '2.5.2'

RAC这框架是非的强大,可以把iOS的事件,代理,KVO都转成信号的传出,学习起来有点难度,如果要运用的是非灵活的话,得掌握了里面的大部分方法 才可以灵活运用。这个框架也运用了链式编程的思想,都是Block的回调。缺点:后期如果有版本变更,框架使用不了的话就很蛋疼了,因为写代码的时候大部分是直接使用框架的方法,如果框架使用不了了,修改起来还是很费劲的。

下面都是一些常用的方法
一、首先介绍下 信号源

RAC的信号源 一般用的话 有三种
RACSignal
RACSubject
RACReplaySubject
1.一个简单的信号的 订阅和发送
RACSignal创建的信号都是冷信号,只有被订阅了 才会立马之前

 //创建的信号一般都是冷信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        [subscriber sendNext:@"我是信号"];
        
        return nil;
    }];
    
    //只有添加了订阅者 才会变成热信号
    [signal subscribeNext:^(id x) {
        
        NSLog(@"接收到的信息---%@",x);
    }];

2.RACSubject创建的信号
跟RACSignal的区别给订阅者发送信号是手动触犯的
得调用[sub sendnEST:@2];

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

3.RACReplaySubject创建的信号
与 RACSubject的 最大的区别就是 可以先发送数据 在订阅信号

- (void)RACReplaySubject {
    //1.创建
    RACReplaySubject *replaySub = [RACReplaySubject subject];
    //2.订阅信号
    [replaySub subscribeNext:^(id x) {
        NSLog(@"11111---%@",x);
    }];
    //遍历所有值发送信号
    
    //3.发送信号
    [replaySub sendNext:@2];
    //RACReplaySubject发送数据
    //1.保存值
    //2.遍历所有订阅者,发送信号
    
    
    [replaySub subscribeNext:^(id x) {
        NSLog(@"22222---%@",x);
    }];
    
    //与 RACSubject的 最大的区别就是 可以先发送数据 在订阅信号
}
一、信号的简单实用

1.可以当代理的实用

//信号做代理使用
- (void)redDelegate {
    RedView *red  = [[RedView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    
    [self.view addSubview:red];
    self.redView = red;
    
    //信号做代理使用
    [red.subjectSignal subscribeNext:^(id x) {
        NSLog(@"代理传值过来:--%@",x);
    }];
}

在RedView.h中的代码
#import 
#import 

@interface RedView : UIView

@property (nonatomic, strong) RACSubject *subjectSignal;

@end


在RedView.m中的代码
- (void)btnClick
{
    
    NSLog(@"按钮点击了");
    
    [self.subjectSignal sendNext:@"哈哈哈哈"];
    
    //之前的代理是这么执行的
//    if ([self.delegate respondsToSelector:@selector(redViewBtnClick:)]) {
//        [self.delegate redViewBtnClick:self.btn];
//    }
    
    
}

2.用来监听某个方法的执行
//模拟器deBug下有模拟内存警告

- (void)daili {
    //用来监听某个对象有没有调用某个方法
    [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
        NSLog(@"模拟内存警告");
    }];

}

3.代替KVO

- (void)racKVO {
    
 //方法1 需要导入头文件  #import "NSObject+RACKVOWrapper.h"
    [self.redView rac_observeKeyPath:@"frame" options:(NSKeyValueObservingOptionNew) observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
         NSLog(@"KVO 1:--%@",value);
    }];
    
    //方法2
    [[self.redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
        NSLog(@"KVO 2:--%@",x);
    }];
}

4.代替按钮的点击事件等

- (void)touchEvent {
    [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"按钮的点击");
    }];
}

5.代替通知

- (void)notifacation {
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"tongzhi" object:nil] subscribeNext:^(id x) {
        NSLog(@"接收到通知");
    }];
}
三 组合信号

组合信号有好多种情况

  1. A B2个信号都执行完 才执行后面的方法
- (void)combienReduce {
    //组合信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"发送请求1");
        [subscriber sendNext:@"1"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"发送请求2");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
            [subscriber sendNext:@"2"];
        });
        return nil;
    }];
    
    //组合信号  只有前2个信号都执行完才执行这个
    [[RACSignal combineLatest:@[signal,signal2] reduce:^id(NSString *str,NSString *str2){
        NSLog(@"%@--%@",str,str2);
        NSString *str3 = [NSString stringWithFormat:@"%@--%@",str,str2];
        return str3;
    }] subscribeNext:^(id x) {
        NSLog(@"最后收到的数据--%@",x);
    }] ;
}

2.类似于 信号合并

//信号组合  多个信号中只要有一个执行就执行
- (void)merge {
    
    RACSubject *subjectA = [RACSubject subject];
    RACSubject *subjectB = [RACSubject subject];
    
    RACSignal *mergeSignal = [subjectA merge:subjectB];
    [mergeSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    
    [subjectA sendNext:@"1"];
    [subjectB sendNext:@"2"];
}

3.把两个信号 压成一个

//把两个信号 压缩成一个  比喻:夫妻关系
- (void)zimpSignal {
    
    RACSubject *subjectA = [RACSubject subject];
    RACSubject *subjectB = [RACSubject subject];
    
    //当所有请求都回来时
    RACSignal *mergeSignal = [subjectA zipWith:subjectB];
    [mergeSignal subscribeNext:^(id x) {
        //返回来的是组合 tuple
        NSLog(@"%@",x);
    }];
    
    [subjectA sendNext:@"1"];
    [subjectB sendNext:@"2"];
    
}

//在控制台打印的是
2018-05-25 15:47:29.771747+0800 RACDemo[64563:2498367]  (
    1,
    2
)

4.两个信号有执行顺序
是按信号顺序来的 必须第一个信号发送完成 而且是 每个信号完成都走一次

//信号合并 比喻:皇上-皇太子关系
- (void)concat {
    
    //组合信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"发送请求1");
        [subscriber sendNext:@"1"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"发送请求2");
        [subscriber sendNext:@"2"];
        return nil;
    }];
    
    //组合信号
    //concat 是按信号顺序来的 必须第一个信号发送完成 而且是 每个信号完成都走一次
    RACSignal *concatSignal = [signal concat:signal2];
    [concatSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    
}
网络模拟多个请求回来后执行的方法
//多请求结束后 执行代码
- (void)network {
    
    //请求热销模块
    RACSignal *hotSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"热销请求数据");
        [subscriber sendNext:@"热销请求数据发送"];
        return nil;
    }];
    
    //请求最新模块
    RACSignal *newSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"最新请求数据");
        [subscriber sendNext:@"最新请求数据发送"];
        return nil;
    }];
    
    
    //当一个界面有多个请求的时候,需保证所有请求都回来 才执行的方法
    //方法的参数必须要跟数组的信号 一一对应
    //方法的参数是每个信号发送的数据
    [self rac_liftSelector:@selector(updateUIWithHot:new:) withSignalsFromArray:@[newSignal,hotSignal]];
    
}

- (void)updateUIWithHot:(NSString *)str1 new:(NSString *)str2 {
    NSLog(@"%@0---%@",str1,str2);
}
四 信号的映射

1.map

//信号的映射
- (void)map {
    
  //1.创建信号
    RACSubject *subject = [RACSubject subject];
    
    //2.绑定信号
    RACSignal *bindSignal = [subject map:^id(id value) {
        
        //修改value的值
        return [NSString stringWithFormat:@"啦啦--%@",value];
    }];
    
    [bindSignal subscribeNext:^(id x) {
        
        NSLog(@"map后的值——--%@",x);
    }];
    
    //发送数据
    [subject sendNext:@"123"];

2.flattenMap
这个是用于处理信号中的信号的

- (void)flattenMap2  {
    
    //flattenMap是用于信号中的信号
    RACSubject *subject = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    
    [[subject flattenMap:^RACStream *(id value) {
        return value;
    }] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    
    //发送信号
    [subject sendNext:subject2];
    [subject2 sendNext:@"2"];
}

//信号的绑定  --  flattenMap
- (void)flattenMap {
    //1.创建信号
    RACSubject *subject = [RACSubject subject];
    
    //2.绑定信号
    RACSignal *bindSignal = [subject flattenMap:^RACStream *(id value) {
        //value 是源信号的内容
        
        //返回修改后的内容  需要这个头文件 #import "RACReturnSignal.h"
        return [RACReturnSignal return:@"ru"];
        
    }];
    
    [bindSignal subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
    }];
    
    //发送数据
    [subject sendNext:@"123"];
}

讲下遇到的坑

1.信号被多次订阅 方法被调用多次 比如

    //创建的信号一般都是冷信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"我要开始发送信号");
        //网络请求的代码
        //比如 requestData
        [subscriber sendNext:@"我是信号"];
        
        return nil;
    }];
    
    //只有添加了订阅者 才会变成热信号
    [signal subscribeNext:^(id x) {
        
        NSLog(@"订阅者1接收到的信息---%@",x);
    }];
    
    [signal subscribeNext:^(id x) {
        
        NSLog(@"订阅者2接收到的信息---%@",x);
    }];
在控制台的打印是
2018-05-25 15:36:02.573591+0800 RACDemo[64317:2483443] 我要开始发送信号
2018-05-25 15:36:02.573740+0800 RACDemo[64317:2483443] 订阅者1接收到的信息---我是信号
2018-05-25 15:36:02.573876+0800 RACDemo[64317:2483443] 我要开始发送信号
2018-05-25 15:36:02.573985+0800 RACDemo[64317:2483443] 订阅者2接收到的信息---我是信号

解决办法

1. //信号被订阅多次 调用多次的Bug
    
    //    1.创建信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        
        NSLog(@"发送请求");
        [subscriber sendNext:@"1"];
        
        return nil;
    }];
    //    2.把信号转成连接类  RACMulticastConnection ---- signal->publish
    RACMulticastConnection *connection = [signal publish];
    //    3.订阅信号
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"第一个订阅者--%@",x);
    }];
    
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"第二个订阅者--%@",x);
    }];
    //    4.连接
    [connection connect];

2、
这里有个关于flattenMap的坑
比如我视图有个按钮 要监听按钮的点击事件 然后map后

- (RACSignal *)signInSignal {
    return [RACSignal createSignal:^RACDisposable *(id subscriber){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [subscriber sendNext:@1];
            [subscriber sendCompleted];
        });
        return nil;
    }];
}

//flattenMap是真确的  打印会打印是信号发送的 1
[[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] flattenMap:^RACStream *(id value) {
        return self.signInSignal;
    }] subscribeNext:^(id x) {
        NSLog(@"最后的值--%@",x);
    }];
    
//这个是不正确的 打印的 是信号
    [[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] map:^RACStream *(id value) {
        return self.signInSignal;
    }] subscribeNext:^(id x) {
        NSLog(@"最后的值--%@",x);
    }];

所以只要是信号中的信号 就得用flattenMap

自己写的githubDemo
https://github.com/rjb0514/-ReactiveCocoaDemo.git

参考文献https://blog.csdn.net/abc649395594/article/details/45933053
https://blog.csdn.net/abc649395594/article/details/46039363
https://blog.csdn.net/abc649395594/article/details/46123379
https://blog.csdn.net/abc649395594/article/details/46233783
https://blog.csdn.net/abc649395594/article/details/46552865

你可能感兴趣的:(ReactiveCocoa学习笔记)