美文网首页
RAC(二)

RAC(二)

作者: dandelionYD | 来源:发表于2018-12-28 19:30 被阅读0次

本demo详见github

下面我们来看看RAC的常见的类的使用

1.RAC常见类-RACSiganl

RACSiganl.h
#import <UIKit/UIKit.h>
@interface RACSiganl : UIViewController
@end

RACSiganl.m
#import "RACSiganl.h"
#import <ReactiveObjC.h>

@interface RACSiganl ()

@end

@implementation RACSiganl

- (void)viewDidLoad {
    [super viewDidLoad];
    [self way1];
    NSLog(@"===================================");
    [self way2];//简写的方式
}

-(void)way1{
    // 1.创建信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3.发送信号
        [subscriber sendNext:@"要发送的内容"];
        // 4.取消信号,如果信号想要被取消,就必须返回一个RACDisposable
        // 信号什么时候被取消:1.自动取消,当一个信号的订阅者被销毁的时候机会自动取消订阅,2.手动取消,
        //block什么时候调用:一旦一个信号被取消订阅就会调用
        //block作用:当信号被取消时用于清空一些资源
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"取消订阅");
        }];
    }];
    // 2. 订阅信号
    //subscribeNext
    // 把nextBlock保存到订阅者里面
    // 只要订阅信号就会返回一个取消订阅信号的类
    RACDisposable *disposable = [signal subscribeNext:^(id x) {
        // block的调用时刻:只要信号内部发出数据就会调用这个block
        NSLog(@"======%@", x);
    }];
    // 取消订阅
    [disposable dispose];
}

-(void)way2{
    [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"1.创建了信号");
        [subscriber sendNext:@"要发送的内容"];
        NSLog(@"4.发送信号完毕");
        return nil;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"2.订阅了信号");
        NSLog(@"3.收到了内容:%@",x);
    }];
}
@end

RACSignal总结:

  • 1.核心:
    • (1)核心:信号类
    • (2)信号类的作用:只要有数据改变就会把数据包装成信号传递出去
    • (3)只要有数据改变就会有信号发出
    • (4)数据发出,并不是信号类发出,信号类不能发送数据
  • 2.使用方法:
    • (1)创建信号
    • (2)订阅信号
  • 3.实现思路:
    • (1)当一个信号被订阅,创建订阅者,并把nextBlock保存到订阅者里面。
    • (2)创建的时候会返回 [RACDynamicSignal createSignal:didSubscribe];
    • (3)调用RACDynamicSignal的didSubscribe
    • (4)发送信号[subscriber sendNext:value];
    • (5)拿到订阅者的nextBlock调用

我们通过源码分析:(command+鼠标左键)


image
image
image

2.RAC常见类-RACSubject

RACSubject_1.m
#import "RACSubject_1.h"
#import <ReactiveObjC.h>
#import "RACSubject_2.h"

@interface RACSubject_1 ()
@property (nonatomic,strong)UIButton  *btn;
@end

@implementation RACSubject_1
- (void)viewDidLoad {
    [super viewDidLoad];
    self.btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 500, 300, 100)];
    [self.btn setTitle:@"开始" forState:UIControlStateNormal];
    [self.btn setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:self.btn];
    [self.btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
}

-(void)jump{
    RACSubject_2 *vc = [[RACSubject_2 alloc]init];
    vc.subject =[RACSubject subject];
    @weakify(self);//防止循环引用
    [vc.subject subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        [self.btn setTitle:x forState:UIControlStateNormal];
    }];
    [self.navigationController pushViewController:vc animated:YES];
}

-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}

@end

RACSubject_2.h
#import <UIKit/UIKit.h>
@class RACSubject;
@interface RACSubject_2 : UIViewController
@property (nonatomic,strong)RACSubject  *subject;
@end

RACSubject_2.m
#import "RACSubject_2.h"
#import <ReactiveObjC.h>

@interface RACSubject_2 ()
@property (nonatomic,strong)UIButton  *btn;
@end

@implementation RACSubject_2
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor greenColor];
    self.btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 500, 300, 100)];
    [self.btn setTitle:@"返回" forState:UIControlStateNormal];
    [self.btn setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:self.btn];
    [self.btn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
}

-(void)back{
    [self.subject sendNext:@"返回了哟"];
    [self.navigationController popViewControllerAnimated:YES]; 
}

-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

分析:我们可以通过RACSubject来实现界面的反向传值

步骤:
 // 1.创建信号
 RACSubject *subject = [RACSubject subject];
 
 // 2.订阅信号
 [subject subscribeNext:^(id x) {
 // block:当有数据发出的时候就会调用
 // block:处理数据
 NSLog(@"%@",x);
 }];
 
 // 3.发送信号
 [subject sendNext:value];
 **注意:~~**
 RACSubject和RACReplaySubject的区别
 RACSubject必须要先订阅信号之后才能发送信号, 而RACReplaySubject可以先发送信号后订阅.
image
image

3.RAC常见类-RACDisposable

#import "RACDisposable_.h"
#import <ReactiveObjC.h>

@interface RACDisposable_ ()
@property (nonatomic,strong)id<RACSubscriber>  subscriber;
@end

@implementation RACDisposable_
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建信号(冷信号)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //发送信号
        [subscriber  sendNext:@"1"];
        
        //n保存订阅者,不会t让他自动消失
        self->_subscriber = subscriber;
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"取消订阅啦");
        }];
    }];
    
    //订阅信号(热信号)
    RACDisposable  *disposable = [signal subscribeNext:^(id  _Nullable x) {
        //信号接收处
        NSLog(@"%@",x);
    }];
    
    //默认一个信号发送完毕会自动取消订阅的
    //因为是用属性 来保存了
    //手动取消订阅
    [disposable dispose];
}

-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

分析:自己可以注释掉[disposable dispose];看看执行的顺序(dealloc)


4.RAC常见类-RACReplaySubject

RACReplaySubject_1.m
#import "RACReplaySubject_1.h"
#import <ReactiveObjC.h>
#import "RACReplaySubject_2.h"

@interface RACReplaySubject_1 ()
@property (nonatomic,strong)UIButton  *btn;
@property (nonatomic,strong)RACReplaySubject  *subject;
@end

@implementation RACReplaySubject_1
- (void)viewDidLoad {
    [super viewDidLoad];
    self.btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 500, 300, 100)];
    [self.btn setTitle:@"开始" forState:UIControlStateNormal];
    [self.btn setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:self.btn];
    [self.btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
    
    // 1.创建信号
    RACReplaySubject *subject = [RACReplaySubject subject];
    // 2.订阅信号
    [subject subscribeNext:^(id x) {
        NSLog(@"第一个订阅者%@",x);
    }];
    [subject subscribeNext:^(id x) {
    NSLog(@"第二个订阅者%@",x);
    }];
    // 3.发送信号
    [subject sendNext:@1];
    [subject sendNext:@2];
    self.subject = subject;

}

-(void)jump{
    RACReplaySubject_2 *vc = [[RACReplaySubject_2 alloc]init];
    vc.subject =  self.subject;
    [self.navigationController pushViewController:vc animated:YES];
}

-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

RACReplaySubject_2.h
#import <UIKit/UIKit.h>
@class RACReplaySubject ;
@interface RACReplaySubject_2 : UIViewController
@property (nonatomic, strong) RACReplaySubject *subject;
@end

RACReplaySubject_2.m
#import "RACReplaySubject_2.h"
#import <ReactiveObjC.h>

@interface RACReplaySubject_2 ()
@property (nonatomic,strong)UIButton  *btn;
@end

@implementation RACReplaySubject_2

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor greenColor];
    self.btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 500, 300, 100)];
    [self.btn setTitle:@"返回" forState:UIControlStateNormal];
    [self.btn setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:self.btn];
    [self.btn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
}

-(void)back{
    [self.subject sendNext:@"返回了哟"];
    [self.navigationController popViewControllerAnimated:YES];
    
}

-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

分析:可以先订阅,然后在发送信号哟


5.RAC常见类-RACSequence

#import "RACSequence_.h"
#import <ReactiveObjC.h>
@interface RACSequence_ ()
@end

@implementation RACSequence_
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *arr = @[@"1",@"2",@"3"];
    NSDictionary*dict =@ {@"key1":@"vaule1",@"key2":@"vaule2",@"key3":@"vaule3"};
    
    //快速遍历字典
    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        //        NSString*key = x[0];
        //        NSString*value = x[1];
        
        RACTupleUnpack(NSString*key,NSString*value) = x;
        NSLog(@"%@--%@",key,value);
    } error:^(NSError * _Nullable error) {
        NSLog(@"error");
    } completed:^{
        NSLog(@"over");
    }];
    
    //快速遍历数组
    [arr.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"error");
    } completed:^{
        NSLog(@"over");
    }];
    
}
@end

在开发中:点击屏幕开始字典数组转模型数组。开发中可以快速高效的遍历数组和字典、字典转模型等


6.RAC常见类-RACCommand

#import "RACCommand_.h"
#import <ReactiveObjC.h>

@interface RACCommand_ ()

@end

@implementation RACCommand_

- (void)viewDidLoad {
    [super viewDidLoad];
  //  [self test1];
    
    NSLog(@"-----------------------------------");
   // [self test2];
    
    NSLog(@"-----------------------------------");
    //[self test3];
    
    NSLog(@"-----------------------------------");
   // [self test4];
    
    NSLog(@"-----------------------------------");
    [self test5];
    
}
// 普通做法
- (void)test1 {
    // RACCommand: 处理事件
    // 不能返回空的信号
    // 1.创建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        //block调用,执行命令的时候就会调用
        NSLog(@"%@",input); // input 为执行命令传进来的参数
        // 这里的返回值不允许为nil
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"执行命令产生的数据"];
            return nil;
        }];
    }];
    
    // 如何拿到执行命令中产生的数据呢?
    // 订阅命令内部的信号
    // ** 方式一:直接订阅执行命令返回的信号
    
    // 2.执行命令
    RACSignal *signal =[command execute:@2]; // 这里其实用到的是replaySubject 可以先发送命令再订阅
    // 在这里就可以订阅信号了
    [signal subscribeNext:^(id x) {
        NSLog(@"----%@",x);
    }];
    
}
// 一般做法
- (void)test2 {
    // 1.创建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        //block调用,执行命令的时候就会调用
        NSLog(@"%@",input); // input 为执行命令传进来的参数
        // 这里的返回值不允许为nil
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"执行命令产生的数据"];
            return nil;
        }];
    }];
    
    // 方式二:
    // 订阅信号
    // 注意:这里必须是先订阅才能发送命令
    // executionSignals:信号源,信号中信号,signalofsignals:信号,发送数据就是信号
    [command.executionSignals subscribeNext:^(RACSignal *x) {
        [x subscribeNext:^(id x) {
            NSLog(@"=====%@", x);
        }];
        NSLog(@"----%@", x);
    }];
    
    // 2.执行命令
    [command execute:@2];
}
// 高级做法
- (void)test3 {
    
    // 1.创建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        // block调用:执行命令的时候就会调用
        NSLog(@"%@", input);
        // 这里的返回值不允许为nil
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"发送信号"];
            return nil;
        }];
    }];
    
    // 方式三
    // switchToLatest获取最新发送的信号,只能用于信号中信号。
    [command.executionSignals.switchToLatest subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    // 2.执行命令
    [command execute:@3];
    
}

// switchToLatest
- (void)test4 {
    // 创建信号中信号
    RACSubject *signalofsignals = [RACSubject subject];
    RACSubject *signalA = [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:@4];
}

// 监听事件有没有完成
- (void)test5 {
    //注意:当前命令内部发送数据完成,一定要主动发送完成
    // 1.创建命令
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        // block调用:执行命令的时候就会调用
        NSLog(@"----%@", input);
        // 这里的返回值不允许为nil
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            // 发送数据
            [subscriber sendNext:@"执行命令产生的数据"];

            // *** 发送完成 **
            [subscriber sendCompleted];
            return nil;
        }];
    }];
    // 监听事件有没有完成
    [command.executing subscribeNext:^(id x) {
        NSLog(@"===%@",x);
        if ([x boolValue] == YES) { // 正在执行
            NSLog(@"当前正在执行%@", x);
        }else {
            // 执行完成/没有执行
            NSLog(@"执行完成/没有执行");
        }
    }];
    
    // 2.执行命令 [command execute:@"哈哈"];
   RACSignal *signal= [command execute:@"哈哈"];
    
   [signal subscribeNext:^(id x) {
        NSLog(@"----%@",x);
    }];
}
@end

RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,比如看事件有没有执行完毕
使用场景:监听按钮点击,网络请求


7.RAC常见类-RACMulticastConnection

#import "RACMulticastConnection_.h"
#import <ReactiveObjC.h>

@interface RACMulticastConnection_ ()

@end

@implementation RACMulticastConnection_

- (void)viewDidLoad {
    [super viewDidLoad];
    [self test];
    
    NSLog(@"---------");
    
    [self test2];
}

- (void)test // 普通写法, 这样的缺点是:每订阅一次信号就得重新创建并发送请求,这样很不友好
{
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // didSubscribeblock中的代码都统称为副作用。
        // 发送请求---比如afn
        NSLog(@"发送请求啦");
        // 发送信号
        [subscriber sendNext:@"请求的内容"];
        return nil;
    }];
    [signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    [signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    [signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    
}

- (void)test2 { // 比较好的做法。 使用RACMulticastConnection,无论有多少个订阅者,无论订阅多少次,我只发送一个。
    // 1.发送请求,用一个信号内包装,不管有多少个订阅者,只想发一次请求
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 发送请求
        NSLog(@"发送请求啦");
        // 发送信号
        [subscriber sendNext:@"请求的内容"];
        return nil;
    }];
    //2. 创建连接类
    RACMulticastConnection *connection = [signal publish];
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    [connection.signal subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
    //3. 连接。只有连接了才会把信号源变为热信号
    [connection connect];
}

@end


打印 :
发送请求啦
请求的内容
发送请求啦
请求的内容
发送请求啦
请求的内容
---------
发送请求啦
请求的内容
请求的内容
请求的内容

分析:

  • 第一种:只要subscribeNext一次,里面就会创建一个订阅者对象,传到createSignal的block里面,然后发送信号内容(执行3次)
  • 第二种:包装到一个里面,3个一次性发出信号内容
  • 即:当有多个订阅者,但是我们只想发送一个信号的时候怎么办?这时我们就可以用RACMulticastConnection,来实现

友情链接:

相关文章

网友评论

      本文标题:RAC(二)

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