最近在学习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. 虚拟机console基础环境配置——sshd安全登陆

    1. 概述2. 配置console的登陆2.1 配置sshd服务2.2 重启sshd服务2.3 无法登陆的问题解决3. 配置密钥登陆3.1 上传公钥的方式3.2 下载密码的方式3.3 虚拟机和宿主机共 ...

  2. java.lang.ClassNotFoundException: com.mysql.jdbc.Drive

    Linux下使用eclipse开发web项目,运行的时候出现 Java.lang.ClassNotFoundException: com.MySQL.jdbc.Driver,解决办法如下: 1.导入M ...

  3. python——在文件存放路径下自动创建文件夹!

    1.a.py文件存放的路径下为(D:\Auto\eclipse\workspace\Testhtml\Test) 2.通过os.getcwd()获取的路径为:D:\Auto\eclipse\works ...

  4. 【BAT面试题系列】面试官:你了解乐观锁和悲观锁吗?

    前言 乐观锁和悲观锁问题,是出现频率比较高的面试题.本文将由浅入深,逐步介绍它们的基本概念.实现方式(含实例).适用场景,以及可能遇到的面试官追问,希望能够帮助你打动面试官. 目录 一.基本概念 二. ...

  5. OsharpNS轻量级.net core快速开发框架简明入门教程-代码生成器的使用

    OsharpNS轻量级.net core快速开发框架简明入门教程 教程目录 从零开始启动Osharp 1.1. 使用OsharpNS项目模板创建项目 1.2. 配置数据库连接串并启动项目 1.3. O ...

  6. 【STM32H7教程】第11章 STM32H7移植SEGGER的硬件异常分析

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第11章       STM32H7移植SEGGER的硬 ...

  7. go语言视频教程和电子书下载

    golang视频教程: https://noxue.com/p/399809259943301 go语言 pdf电子书: Design Pattern In Go[go语言设计模式].pdf Go P ...

  8. 将本地文件传输到GitHub

    统一概念: 工作区:增删文件和内容 暂存区:键入命令 git add 改动的文件,此次改动就放到了 『暂存区』 本地仓库 :键入命令 git commit ,此次改动就放到了『本地仓库』,每个 com ...

  9. Linux创建普通用户

    声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 1.创建用户,-m表示同时创建用户家目录 sudo useradd -m hadoop 2.为创建的hadoop用户设置密码 sudo passwd ...

  10. uni-app—从安装到卸载

    uni-app实现了一套代码,同时运行到多个平台.支持iOS模拟器.Android模拟器.H5.微信开发者工具.支付宝小程序Studio.百度开发者工具.字节跳动开发者工具 工具安装 开发uni-ap ...