zoukankan      html  css  js  c++  java
  • RAC(ReactiveCocoa)介绍(一)

    最近在学习RAC,之前在iOS工作中,类之间的传值,无非是block、delegate代理、KVO和Notification等这几种方法。在RAC中,同样具备替代block、delegate代理、KVO和Notification,UI target、定时器timer、数据结构等各种方式。依靠FRP(响应式函数编程),RAC方法本身更加简单明了,通过提供信号的方式(RACSignal)可以捕捉到当前以及未来的属性值的变化,而且无需持续观察和更新代码。可直接在block中将逻辑代码加入其中,使得代码紧凑,更加直观。

    先来介绍ObjC版本,使用cocoaPods在podfile中添加 pod 'ReactiveObjC', '~> 3.1.0' ,然后pod install一下。在项目中#import <ReactiveObjC.h>,建议放入pch头文件中。

    通过RAC提供的方法与系统提供的方法分别进行对比,先来感受下RAC的强大之处

    一、UIButton

    1.1 传统方式

    - (UIButton *)testBtn{
        if (!_testBtn) {
            _testBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            _testBtn.backgroundColor = [UIColor redColor];
            _testBtn.frame = CGRectMake((UIScreen.mainScreen.bounds.size.width - 60)/2, (UIScreen.mainScreen.bounds.size.height - 60)/2, 60, 60);
            [_testBtn addTarget:self action:@selector(tapAction) forControlEvents:UIControlEventTouchUpInside];
        }
        return _testBtn;
    }
    
    - (void)tapAction{
        NSLog(@"你好");
    }

    运行结果为

    1.2 RAC

    - (void)btnRAC{
        [[self.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(__kindof UIControl * _Nullable x) {
            NSLog(@"RAC按钮点击了");
        }];
    }

    运行结果如下:

    二、KVO

    2.1 传统KVO

    KVO在使用时,必须在- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context中实现针对KVO监听属性值变化的处理,而且对于KeyPath书写容易产生手写错误。在对应类dealloc时,KVO还必须要进行remove操作,否则会程序crash。
    - (void)KVO{
        [self orignKVO];
        [self RACKVO];
    }
    
    - (void)orignKVO{
        [self.testLabel addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        if ([keyPath isEqualToString:@"text"] && object == self.testLabel) {
            NSLog(@"%@",change);
        }
    }

    2.2 RAC版

    在使用RAC代替KVO时,不仅能大大增加代码可读性,而且RACObserve(<#TARGET#>, <#KEYPATH#>)宏定义中keyPath可以代码提示出target中的属性成员变量,降低手写代码错误的可能性。

    [RACObserve(self.testLabel, text)subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];

    三、delegate代理

    以UITextField为例,当需要对UITextField逻辑处理时,往往需要实现其各类代理方法,大大增加了代码量。当使用RAC之后

    - (void)KVODelegate{
        [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:)fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
            NSLog(@"%@",x);
        }];
        self.textField.delegate = self;
    }

    @selector方法选择器中键入要实现的代理方法,代理名称声明为对应的代理名称。block代码块中,当触发监听的代理方法时返回元组类型数据,与swift中的元组类型有所区别,此处的元组看起来更像是数组。

    四、Notification通知

    - (void)RACNotification{
        [[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardDidHideNotification object:nil]subscribeNext:^(NSNotification * _Nullable x) {
            NSLog(@"%@",x);
        }];
    }

    五、定时器timer

    - (void)RACTimer{
        //主线程每两秒执行一次
        [[RACSignal interval:2.0 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //创建一个新线程
        [[RACSignal interval:1 onScheduler:[RACScheduler schedulerWithPriority:(RACSchedulerPriorityHigh)name:@"com.reactiveCocoa.RACScheduler.mainTreadScheduler"]]subscribeNext:^(NSDate * _Nullable x) {
            NSLog(@"%@",[NSThread currentThread]);
        }];
        
    }

    六、数组与字典

    遍历元素
    - (void)RACSequence{
        NSArray *array = @[@"乔布斯",@"苹果",@"发达"];
        [array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        NSDictionary *dict = @{@"name":@"dragon",@"type":@"fire"};
        [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
            RACTwoTuple *tuple = (RACTwoTuple *)x;
            NSLog(@"key == %@, value == %@",tuple[0],tuple[1]);
        }];
    }

    七、RAC使用基本流程

    RAC基本使用方法与流程

    - (void)RACBaseUse{
        //RAC基本使用
        RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            [subscriber sendNext:@"sendOneMessage"];
            //发送error信号
            NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:1001 userInfo:@{@"errorMsg":@"this is a error message"}];
            [subscriber sendError:error];
            
            //4. 销毁信号
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"signal已销毁");
            }];
        }];
        
        //2.1 订阅信号
        [signal subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@",x);
        }];
        
        //2.2 针对实际中可能出现的逻辑错误,RAC提供了订阅error信号
        [signal subscribeError:^(NSError * _Nullable error) {
            NSLog(@"%@",error);
        }];
    }

    以上代码中,subscribeNext作用为订阅信号,可在该block中输入逻辑相关代码块。

    注意问题,可能也会有循环引用问题产生,如下:

    - (void)RACFilter{
        @weakify(self);
        [[self.textField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
            //过滤判断条件
            @strongify(self)
            if (self.textField.text.length >= 6) {
                self.textField.text = [self.textField.text substringToIndex:6];
                self.testLabel.text = @"已经到6位了";
                self.testLabel.textColor = [UIColor redColor];
            }
            return value.length <= 6;
            
        }] subscribeNext:^(NSString * _Nullable x) {
            //订阅逻辑区域
            NSLog(@"filter过滤后的订阅内容:%@",x);
        }];
    }

    以此来避免出现block的循环引用。

     稍后会在后续的文章里继续介绍如何使用,以及RAC信号流程原理。demo代码放到GitHub上。

    demo连接:https://github.com/zxy1829760/RAC-1-

  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/10442051.html
Copyright © 2011-2022 走看看