zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    行为型模式之备忘录模式
    行为型模式之中介者模式
    行为型模式之迭代器模式
    行为型模式之解释器模式
    行为型模式之命令模式
    行为型模式之职责链模式
    结构型模式之代理模式
    结构型模式之享元模式
    进入Linux的新世界
    302转向与网址劫持(转)
  • 原文地址:https://www.cnblogs.com/cui-cui/p/10065192.html
Copyright © 2011-2022 走看看