之前我们初步认识了RAC的设计思路跟实现方式, 现在我们再来看看如果使用它以及它能帮我们做什么

One of the major advantages of RAC is that it provides a single, unified approach to dealing with asynchronous behaviors, including delegate methods, callback blocks, target-action mechanisms, notifications, and KVO.

官方是这样说的, RAC为我们提供了简单便捷实现代理 / block回调 / 事件 / 通知 / KVO的方式

我们先看RAC如何帮助我们快速实现KVO

首先我们新建一个Student类, 给它一个age的属性

#import <Foundation/Foundation.h>

@interface Student : NSObject

@property (nonatomic, strong) NSString *age;

@end

下面我们看一个简单的如何使用RAC来实现KVO

    Student *stu = [[Student alloc] init];

    // RAC KVO
[RACObserve(stu, age) subscribeNext:^(id _Nullable x) { NSLog(@"stu的age改变为: %@", x);
}]; stu.age = @"";

运行看看:

-- ::19.704 RAC[:] stu的age改变为: (null)
-- ::19.704 RAC[:] stu的age改变为:

很方便对吧, 不用我们去add observe, 不用出来观察事件, 也不用我们去移除关注

不过大家注意到了没, 这里添加关注后block立即执行了一次, 大家可以依据实际项目情况加个条件判断做处理.

这里其实RAC还为我们提供了除了subscriber以外的操作,  后面再介绍给, 现在我们主要先来看RAC是怎么替我们做KVO的

我们再看看RAC如何帮我们实现target-action

我们创建一个项目, 在controller中添加一个button, 然后给button添加一个点击事件

如果是常规写法的话, 在创建完button后创建一个点击响应方法, 然后通过addTarget把响应方法跟button及事件绑定到一起

大概类似这样:

[button addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];

- (void)btnAction {

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

在上一篇我们提到过这样的劣势, 当代码比较多的时候结构容易乱, 维护的时候也不好查找方法

我们看看RAC如何帮我们优雅的实现

RAC为我们提供了rac_signalForControlEvents来处理UIControllerEvent, 我们试试看

    [[button
rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(__kindof UIControl * _Nullable x) { NSLog(@"%@", x);
}];

因为不知道这里的x是什么, 我们直接打印看看结果

-- ::59.654 RAC[:] <UIButton: 0x7f95e0d069f0; frame = ( 350.5;  ); opaque = NO; layer = <CALayer: 0x6080000269a0>>

当我们点击按钮打印了上面这些,  是我们创建的button对象

那么加入需要点击的时候给button更换背景图片或者标题就可以在这里处理了, 我们用改变颜色举例

    [[button
rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(__kindof UIControl * _Nullable x) { x.backgroundColor = [UIColor redColor];
}];

运行后, 就可以看到如果点击按钮背景就会变成红色, 如果有点击事件也可以放在这里

但如果点击后要处理的逻辑比较多, 代码超过三行建议大家单独写一个方法供调用, 以免破坏代码的结构

RAC这样的使用方式, 让我的代码逻辑更加清晰紧凑了, 我们再看一个添加手势的例子

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];

    [[tap
rac_gestureSignal]
subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) { NSLog(@"点击了屏幕");
NSLog(@"x: %@", x);
}]; [self.view addGestureRecognizer:tap];

运行看看:

-- ::59.246 RAC[:] 点击了屏幕
-- ::59.247 RAC[:] x: <UITapGestureRecognizer: 0x6000001a5160; state = Ended; view = <UIView 0x7fb932d03780>; target= <(action=sendNext:, target=<RACPassthroughSubscriber 0x60800003a920>)>>

这里x是一个手势, 我们可以直接拿来使用, 比如我们改变下添加手势这个view的颜色

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];

    [[tap
rac_gestureSignal]
subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) { NSLog(@"点击了屏幕");
NSLog(@"x: %@", x);
x.view.backgroundColor = [UIColor redColor];
}]; [self.view addGestureRecognizer:tap];

这样手势的初始化, 方法等等都在一起, 让代码一目了然

接下来我们看看RAC如何帮我们实现通知的

我们常规的通知应该是这样, 在要接收通知的地方添加关注通知并写上通知事件

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiAction) name:@"noti" object:nil];

- (void)notiAction {

    NSLog(@"接到了通知");
}

然后在对应的地方发送通知

[[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil userInfo:nil];

RAC会怎么帮我们实现呢?

    [[[NSNotificationCenter defaultCenter]
rac_addObserverForName:@"noti" object:nil]
subscribeNext:^(NSNotification * _Nullable x) { NSLog(@"接到了通知");
}];

发送通知iOS已经很简单了, RAC没有做重复工作但帮我们把添加关注通知的方法改进了, 可以让事件和通知关注在一起

这样接口就清晰了

那么RAC如果帮我们实现代理呢?

我用UIAlertView给大家举个例子, 虽然苹果已经不推荐用这个 不过我们拿来当例子用用看

先写一个常规的AlertView

#import "ViewController.h"
#import <ReactiveObjC.h> @interface ViewController ()<UIAlertViewDelegate> @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]; [alertView show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == ) { NSLog(@"点击了Cancel按钮");
} else { NSLog(@"点击了Ok按钮");
}
} @end

初始化alertView, 实现代理方法 这是我们常规的用法

那么我们再看看RAC如何做

#import "ViewController.h"
#import <ReactiveObjC.h> @interface ViewController ()<UIAlertViewDelegate> @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]; [[self
rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
subscribeNext:^(RACTuple * _Nullable x) { NSLog(@"%@", x);
}]; [alertView show]; } @end

RAC为我们提供了一个rac_signalForSelector: fromProtoc方法帮我们实现代理

我们把x打印看看

-- ::07.138 RAC[:] <RACTuple: 0x6080000149f0> (
"<UIAlertView: 0x7fc7dfc0c620; frame = (0 0; 0 0); layer = <CALayer: 0x6000002218a0>>", )

我们看看这个RACTuple

@interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>

@property (nonatomic, readonly) NSUInteger count;

/// These properties all return the object at that index or nil if the number of
/// objects is less than the index.
@property (nonatomic, readonly, nullable) id first;
@property (nonatomic, readonly, nullable) id second;
@property (nonatomic, readonly, nullable) id third;
@property (nonatomic, readonly, nullable) id fourth;
@property (nonatomic, readonly, nullable) id fifth;
@property (nonatomic, readonly, nullable) id last;

打印看看

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Delegate Test" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];

    [[self
rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]
subscribeNext:^(RACTuple * _Nullable x) { NSLog(@"%@", x);
NSLog(@"first: %@", x.first);
NSLog(@"second: %@", x.second);
NSLog(@"third: %@", x.third);
NSLog(@"fourth: %@", x.fourth);
NSLog(@"fifth: %@", x.fifth);
NSLog(@"last: %@", x.last);
}]; [alertView show];

结果为:

-- ::26.089 RAC[:] first: <UIAlertView: 0x7f814e604420; frame = ( ;  ); layer = <CALayer: 0x60800003a3e0>>
-- ::26.090 RAC[:] second:
-- ::26.090 RAC[:] third: (null)
-- ::26.090 RAC[:] fourth: (null)
-- ::26.091 RAC[:] fifth: (null)
-- ::26.091 RAC[:] last:

第一个是alert本身, 第二个是index, 然后可以按我们的需要做处理了

另外要注意的是用RAC写代理是有局限的,它只能实现返回值为void的代理方法

先到这里, 现在我们知道我们能用RAC做什么了

下次我们继续看RAC的具体用法

函数响应式编程及ReactiveObjC学习笔记 (二)的更多相关文章

  1. 函数响应式编程及ReactiveObjC学习笔记 (-)

    最近无意间看到一个视频讲的ReactiveObjC, 觉得挺好用的 但听完后只是了解个大概. 在网上找了些文章, 有的写的比较易懂但看完还是没觉得自己能比较好的使用RAC, 有的甚至让我看不下去 这两 ...

  2. 函数响应式编程及ReactiveObjC学习笔记 (三)

    之前讲了RAC如何帮我们实现KVO / 代理 / 事件 / 通知 今天先不去分析它的核心代码, 我们先看看ReactiveObjC库里面一些特别的东西,  如果大家点开ReactiveObjC目录应该 ...

  3. 函数响应式编程及ReactiveObjC学习笔记 (四)

    今天我们继续看其他的类别 UIImagePickerController+RACSignalSupport.h #import <UIKit/UIKit.h> @class RACDele ...

  4. 函数响应式编程(FRP)框架--ReactiveCocoa

    由于工作原因,有段时间没更新博客了,甚是抱歉,只是,从今天開始我又活跃起来了,哈哈,于是决定每周更新一博.大家互相学习.交流. 今天呢.讨论一下关于ReactiveCocoa,这个採用函数响应式编程( ...

  5. 函数响应式编程(FRP)—基础概念篇

    原文出处:http://ios.jobbole.com/86815/. 一函数响应式编程 说到函数响应式编程,就不得不提到函数式编程,他们俩有什么关系呢?今天我们就详细的解析一下他们的关系. 现在下面 ...

  6. RxJS入门之函数响应式编程

    一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程⽅式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的⼀种编程⽅式. //命令式编程: fun ...

  7. 函数响应式编程(FRP)思想-Callback风格

    序 ReactiveCocoa是IOS广为使用的技术框架,而ReactiveCocoa的核心思想就FRP.FRP不同于JAVA的object-oriented和AOP,FRP能让你的代码像数学一样简洁 ...

  8. ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!

    简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模 ...

  9. 函数响应式编程(FRP)从入门到”放弃”——基础概念篇

    前言 研究ReactiveCocoa一段时间了,是时候总结一下学到的一些知识了. 一.函数响应式编程 说道函数响应式编程,就不得不提到函数式编程,它们俩到底有什么关系呢?今天我们就详细的解析一下他们的 ...

随机推荐

  1. TreeSet集合排序方式二:定制排序Comparator

    Comparator有两种实现方式: 1,匿名内部类 2,创建一个类用于实现Comparator,该类创建的对象就是比较器 Person类 public class Person implements ...

  2. 【原创+史上最全】Nginx+ffmpeg实现流媒体直播点播系统

    #centos6.6安装搭建nginx+ffmpeg流媒体服务器 #此系统实现了视频文件的直播及缓存点播,并支持移动端播放(支持Apple和Android端) #系统需要自行安装,流媒体服务器配置完成 ...

  3. eclipse在线安装s

    1. 打开eclipse软件,点击菜单栏的help-->Install New Software 2. 在弹出来的安装窗口中,点击add按钮,然后输入svn安装地址:http://subclip ...

  4. 常用SHELL命令

    1.查看版本号cat /proc/version; uname -a; uname -r 2.查看用户组cat /etc/group 3.查看当前用户组 groups 4.查看当前用户 whoami ...

  5. ecshop收货地址货到付款修改

    用户选择某些地址时,支付方式里则可以依据此地址来对货到付款选项进行显示或隐藏.目前仅与顺丰合作,以顺丰提供的数据为准. 使用到的数据库分别如下: ecs_region//地方数据,PRIMARY KE ...

  6. sodu 命令场景分析

    摘自:http://www.cnblogs.com/hazir/p/sudo_command.html sudo 命令情景分析   Linux 下使用 sudo 命令,可以让普通用户也能执行一些或者全 ...

  7. 360安全检测出的WordPress漏洞的修复方法

    1.跨站脚本攻击(XSS) 这个漏洞注意是因为用户评论可以提交代码,有安全风险.虽然你的WordPress以及是最新版,但是你的WordPress主题却不一定跟着更新!因此,需要稍微修改一下评论相关的 ...

  8. js中的函数

    [函数的声明及调用] 基础知识 1.函数声明的格式: function 函数名(参数1,参数2,....){ //函数体 return 结果: } >>>函数调用的格式: 直接调用: ...

  9. laydate时间插件更换皮肤

    <script> ;!function(){ laydate.skin('molv'); laydate({ elem: '#demo' }) }();</script>

  10. 淘宝tairKV分布式

    Tair是什么 Tair是由淘宝开发的key/value方案,系统默认支持基于内存和文件的存储引擎,对应于通常我们所说的缓存和持久化存储,这里可以获取更多关于tair的信息,淘宝团队介绍,Tair在淘 ...