最近在学习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 - )/, (UIScreen.mainScreen.bounds.size.height - )/, , );
[_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: 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[],tuple[]);
}];
}

七、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: 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 >= ) {
self.textField.text = [self.textField.text substringToIndex:];
self.testLabel.text = @"已经到6位了";
self.testLabel.textColor = [UIColor redColor];
}
return value.length <= ; }] subscribeNext:^(NSString * _Nullable x) {
//订阅逻辑区域
NSLog(@"filter过滤后的订阅内容:%@",x);
}];
}

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

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

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

RAC(ReactiveCocoa)介绍(一)的更多相关文章

  1. RAC(ReactiveCocoa)使用方法(一)

    RAC(ReactiveCocoa)使用方法(一) RAC(ReactiveCocoa)使用方法(二) 什么是RAC? 最近回顾了一下ReactiveCocoa的方法,也看了一些人的文章,现写篇文章总 ...

  2. RAC(ReactiveCocoa)使用方法(二)

    RAC(ReactiveCocoa)使用方法(一) RAC(ReactiveCocoa)使用方法(二) 上篇文章:RAC(ReactiveCocoa)使用方法(一) 中主要介绍了一些RAC中常见类的用 ...

  3. RAC(ReactiveCocoa)概括

    ReactiveCocoa(简称RAC,以下都用RAC)是github团队开源的一套基于Cocoa并且具有FRP(Functional Reactive Programming-响应式编程)特性的框架 ...

  4. ReactiveCocoa基础知识内容

    本文记录一些关于学习ReactiveCocoa基础知识内容,对于ReactiveCocoa相关的概念如果不了解可以网上搜索:RACSignal有很多方法可以来订阅不同的事件类型,ReactiveCoc ...

  5. 关于Oracle的rac集群和mysql Galera Cluster的想法

    到了新公司,公司用的是rac,我比较熟悉mysql第三方的集群方案Galera Cluster这类多主集群, 下面是我参考了他人对rac的介绍,然后和mysql方案进行的臆测级别的分析对比. rac和 ...

  6. oracle rac 学习(转载)

    一. RAC 并发 RAC 的本质是一个数据库,运行在多台计算机上的数据库,它的主要任务是数据库就是事务处理,它通过 Distributed Lock Management(DLM:分布式锁管理器)  ...

  7. [干货分享]一篇可能会让你爱上MVVM与ReactiveCocoa的文章

    概要 在此工程中,本文将讨论将MVC改造为MVVM需要的一些基本方法,同时会适当穿插部分关于MVVM概念性的讨论!本文最大的意义在于,提供了一种读者可以复现的方式,逐步引出从MVC向MVVM尽可能平滑 ...

  8. 李洪强iOS经典面试题下

    李洪强iOS经典面试题下 21. 下面的代码输出什么? @implementation Son : Father - (id)init { self = [super init]; if (self) ...

  9. iOS学习笔记39-ReactiveCocoa入门

    FRP,全称为Functional Reactive Programming,是一种响应变化的编程范式,最近几年比较火,大概的理解就像这样: 当a的值或者b的值发生变化时,c的值会自动响应a的值或b的 ...

随机推荐

  1. Postman-----如何导入和导出

    此处介绍2种导出和导入的操作方法,一种是通过分享link,另一种是导出json文件,再次导入,个人推荐link的方式,简单方便,下面将详细介绍. 第一种:分享链接,导入链接的方式 1.1.生成link ...

  2. Centos6.4 + mysql-5.6.38-linux-glibc2.12-x86_64.tar 实现mysql主从复制

    mysql安装方法:http://www.cnblogs.com/lin3615/p/4376224.html 用到的是两台服务器 主:192.168.1.106 从:192.168.1.69 1.在 ...

  3. a标签跳转之前加点击事件

    ①在html标签中出现提示 <a href="http://www.baidu.com" onclick="if(confirm('确认百度吗?')==false) ...

  4. Apache Mina -2

    我们可以了解到 mina是个异步通信框架,一般使用场景是服务端开发,长连接.异步通信使用mina是及其方便的.不多说,看例子. 本次mina 使用的例子是使用maven构建的,过程中需要用到的jar包 ...

  5. python基于selenium实现自动删除qq空间留言板

    py大法好,让你解放双手. 脚本环境 python环境,selenium库,Chrome webdriver驱动等. 源码 # coding=utf-8 import datetime import ...

  6. java游戏开发杂谈 - 创建一个窗体

    package game1; import javax.swing.JFrame; /** * java游戏开发杂谈 * ---demo1:创建一个窗体 * * @author 台哥 * @date ...

  7. 国内开源社区巨作AspectCore-Framework入门

    前些天和张队(善友),lemon(浩洋),斌哥(项斌)等MVP大咖一块儿吃饭,大家聊到了lemon名下的AOP这个项目,我这小白听得一脸懵逼,后面回来做了一下功课,查了下资料,在lemon的Githu ...

  8. Netty源码—七、内存释放

    Netty本身在内存分配上支持堆内存和直接内存,我们一般选用直接内存,这也是默认的配置.所以要理解Netty内存的释放我们得先看下直接内存的释放. Java直接内存释放 我们先来看下直接内存是怎么使用 ...

  9. Docker最全教程之使用Docker搭建Java开发环境(十七)

    前言 Java是一门面向对象的优秀编程语言,市场占有率极高,但是在容器化实践过程中,发现官方支持并不友好,同时与其他编程语言的基础镜像相比(具体见各语言镜像比较),确实是非常臃肿. 本篇仅作探索,希望 ...

  10. 【响应式编程的思维艺术】 (5)Angular中Rxjs的应用示例

    目录 一. 划重点 二. Angular应用中的Http请求 三. 使用Rxjs构建Http请求结果的处理管道 3.1 基本示例 3.2 常见的操作符 四. 冷热Observable的两种典型场景 4 ...