ReactiveObjC 学习笔记

ReactiveObjC (一般来说又叫做ReactiveCocoa或者RAC)是一个基于响应式编程的Objective-C的框架。使用起来真的很强大,可以用来代替监听事件方法,代替KVO,代替通知代理等。

一.使用

使用pods导入:

pod 'ReactiveObjC', '~> 3.1.0'

二.流程分析

RAC核心思想:创建信号-订阅信号-发送信号,主要有三个关键类:

1、RACSignal信号
RACSignal是各种信号的基类,其中RACDynamicSignal是用的最多的动态信号

2、RACSubscriber订阅者
RACSubscriber是实现了RACSubscriber协议的订阅者类,这个协议定义了4个必须实现的方法

- (void)sendNext:(nullableid)value; //常见
- (void)sendError:(nullableNSError*)error; //常见
- (void)sendCompleted; //常见
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;


3、 RACDisposable清洁工
RACDisposable主要是对资源的释放处理,其中使用 RACDynamicSignal时,会创建一个 RACCompoundDisposable管理清洁工对象。其内部定义了两个数组,一个是 _inlineDisposables[2]固定长度2的 A fast array,超出2个对象的长度由 _disposables数组管理, _inlineDisposables数组速度快,两个数组都是线程安全的。
 
 
三.具体使用
 
 1、rac_textSignal 文本监听信号,可以减少对代理方法的依赖
 

  UITextField*field = [[UITextField alloc]initWithFrame:CGRectMake(50, 50, 200, 50)];

    field.backgroundColor = [UIColor grayColor];

    [self.view addSubview:field];

    //UITextField创建了一个 `textSignal`的信号,并订阅了该信号

    //当UITextField的内容发生改变时,就会回调subscribeNext

    [[field rac_textSignal] subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"text changed = %@", x);

    }];

2、filter 对订阅的信号进行筛选

    [[field.rac_textSignal filter:^BOOL(NSString * _Nullable value) {

        return value.length > 5;

    }] subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"输入框内容%@",x);

    }];

3、ignore 对订阅的信号进行过滤

    [[field.rac_textSignal ignore:@"666"] subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"输入框内容%@",x);

    }];

 
4、rac_signalForControlEvents 创建事件监听信号(UIButton)

    //创建一个按钮

    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 70, 70)];

    btn.backgroundColor = [UIColor redColor];

    [self.view addSubview:btn];

    btn.tag = 1001;

    //监听点击事件

    [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {

        NSLog(@"按钮点击了");

    }];

5、代替KVO

    //创建一个按钮

    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 70, 70)];

    btn.backgroundColor = [UIColor redColor];

    [self.view addSubview:btn];

    btn.tag = 1001;

    //监听点击事件

    [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {

        NSLog(@"按钮点击了");

        x.frame = CGRectMake(100, 100, 200, 200);

    }];

    [[btn rac_valuesAndChangesForKeyPath:@"frame" options:(NSKeyValueObservingOptionNew) observer:self] subscribeNext:^(RACTwoTuple<id,NSDictionary *> * _Nullable x) {

        NSLog(@"frame改变了%@",x.second);

    }];

或者使用如下方法,#define RAC(TARGET, ...)这个宏定义是将对象的属性变化信号与其他信号关联

    [RACObserve(btn, frame) subscribeNext:^(id  _Nullable x) {

        NSLog(@"frame改变了%@",x);

    }];

6、代替通知

//@property (nonatomic, strong) RACDisposable *keyboardDisposable;
self.keyboardDisposable = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) { NSLog(@"%@ 键盘弹起", x); // x 是通知对象 }]; 

注意:rac_addObserverForName同样需要移除监听。RAC通知监听会返回一个RACDisposable清洁工的对象,在dealloc中销毁信号,信号销毁时,RAC在销毁的block中移除了监听

- (void)dealloc {
    [_keyboardDisposable dispose];
}

7、代替timer循环执行

    [[RACSignal interval:1.0 onScheduler:[RACScheduler scheduler]] subscribeNext:^(NSDate * _Nullable x) {

        NSLog(@"%@",x);

    }];

8、数组遍历

    NSArray*array = @[@"1", @"2", @"3", @"4", @"5"];

    [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

        NSLog(@"数组内容:%@",x);

    }];

9、字典遍历

    NSDictionary*dictionary = @{@"key1":@"value1", @"key2":@"value2", @"key3":@"value3"};

    [dictionary.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

//        NSLog(@"字典内容:%@",x);

        RACTupleUnpack(NSString*key,NSString*value) = x;

        NSLog(@"字典内容:%@:%@",key,value);

    }];

10、代替代理

新建一个自定义view——RACView,重写初始化方法。

在RACView.h文件中定义一个rac信号属性

@property (nonatomic,strong)RACSubject *btnClickSingle;

在.m文件中重写初始化方法,发送信号
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor redColor]; //创建一个按钮 UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 70, 70)]; btn.backgroundColor = [UIColor redColor]; [self addSubview:btn]; [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) { //发送信号 [self.btnClickSingle sendNext:@"按钮点击咯"]; }]; } return self; } -(RACSubject *)btnClickSingle{ if (!_btnClickSingle) { _btnClickSingle = [RACSubject subject]; } return _btnClickSingle; }


在ViewController中
//只能代替没有返回值的代理
-(void)demo3{
    RACView *racView = [[RACView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)]; [self.view addSubview:racView]; //替代了代理把值从racView中传了过来。 [racView.btnClickSingle subscribeNext:^(id _Nullable x) { //要传多个值,,可以传一个集合 NSLog(@"%@",x); }]; }

11.用来给某个对象的某个属性绑定信号,只要产生信号内容,就把内容给属性赋值

    UITextField*field = [[UITextField alloc]initWithFrame:CGRectMake(50, 120, 200, 50)];

    field.backgroundColor = [UIColor greenColor];

    [self.view addSubview:field];

    UILabel*label = [[UILabel alloc]initWithFrame:CGRectMake(50, 50, 200, 50)];

    [self.view addSubview:label];

    RAC(label,text) = field.rac_textSignal;

12.登录按钮的状态根据输入框内容改变

    UITextField*userNameTF = [[UITextField alloc]initWithFrame:CGRectMake(40, 70, 200, 50)];

    UITextField*passwordTF = [[UITextField alloc]initWithFrame:CGRectMake(40, 130, 200, 50)];

    userNameTF.placeholder = @"请输入用户名";

    passwordTF.placeholder = @"请输入密码";

    [self.view addSubview:userNameTF];

    [self.view addSubview:passwordTF];

    UIButton*loginBtn = [[UIButton alloc]initWithFrame:CGRectMake(40, 180, 200, 50)];

    [loginBtn setTitle:@"马上登录" forState:UIControlStateNormal];

    [self.view addSubview:loginBtn];

    RAC(loginBtn, enabled) = [RACSignal combineLatest:@[userNameTF.rac_textSignal, passwordTF.rac_textSignal] reduce:^id _Nullable(NSString * username, NSString * password){

        return @(username.length >= 11 && password.length >= 6);

    }];

    RAC(loginBtn,backgroundColor) = [RACSignal combineLatest:@[userNameTF.rac_textSignal, passwordTF.rac_textSignal] reduce:^id _Nullable(NSString * username, NSString * password){

        return (username.length >= 11 && password.length >= 6) ? [UIColor redColor] : [UIColor grayColor];

    }];

13.避免循环引用,外部用@weakify(self),内部用@strongify(self)

    // @weakify() 宏定义

    @weakify(self) //相当于__weak typeof(self) weakSelf = self;

    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

        @strongify(self//相当于__strong typeof(weakSelf) strongSelf = weakSelf;

        NSLog(@"%@",self.view);

        return nil;

    }];

    _signal = signal;

参考链接:https://www.jianshu.com/p/14075b5ec5ff

       https://www.jianshu.com/p/6af75a449d90 

原理及流程简介:https://www.jianshu.com/p/fecbe23d45c1

猜你喜欢

转载自www.cnblogs.com/cui-cui/p/10065192.html