作为函数式编程和响应式编程的代表ReactiveCocoa,自一出世便受到广大码农的热爱,结合MVVM编程模式,不仅能够方便的处理各种交互事件、降低模块间的耦合性,还能简化项目结构,降低阅读和维护的成本。本文从应用的角度,介绍一下ReactiveCocoa常用类的用法:

一、RACSignal

1. 功能

这是ReactiveCocoa的核心类,用来表示数据传递,只要有数据变化,信号内部受到数据后,就会马上发出数据

2. 使用步骤

  • 创建信号
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
  • 订阅信号
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
  • 发送信号
- (void)sendNext:(id)value

具体使用如下:

	// RACSignal底层实现:
// 1.创建信号,首先把didSubscribe保存到信号中,还不会触发。
// 2.当信号被订阅,也就是调用signal的subscribeNext:nextBlock
// 2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中。
// 2.1 subscribeNext内部会调用siganl的didSubscribe
// 3.siganl的didSubscribe中调用[subscriber sendNext:@1];
// 3.1 sendNext底层其实就是执行subscriber的nextBlock // 1.创建信号
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id subscriber) { // block调用时刻:每当有订阅者订阅信号,就会调用block。 // 2.发送信号
[subscriber sendNext:@1]; // 如果不在发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号。
[subscriber sendCompleted]; // 执行完信号后进行的清理工作,如果不需要就返回 nil
return [RACDisposable disposableWithBlock:^{ // block调用时刻:当信号发送完成或者发送错误,就会自动执行这个block,取消订阅信号。 // 执行完Block后,当前信号就不在被订阅了。 NSLog(@"信号被销毁");
}];
}]; // 3.订阅信号,才会激活信号.
[siganl subscribeNext:^(id x) {
// block调用时刻:每当有信号发出数据,就会调用block.
NSLog(@"接收到数据:%@",x);
}];

3. RACSubscriber

这是信号的订阅者,本质是一个协议,遵守这个协议的类对象,并且实现协议方法就可以成为一个订阅者

4. RACDisposable

这是用于取消订阅或者清理资源的类,当信号发送完成或者发送错误的时候会自动触发调用

二、RACSubject

1. 功能

信号的提供者,被成为是信号的信号,即自己可以充当信号,也能够发送信号,常用来代理代理。

2. 使用步骤

  • 创建信号
[RACSubject subject]
  • 订阅信号
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
  • 发送信号
sendNext:(id)value

具体使用如下:

	// RACSubject:底层实现和RACSignal不一样。
// 1.调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了。
// 2.调用sendNext发送信号,遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。 // 1.创建信号
RACSubject *subject = [RACSubject subject]; // 2.订阅信号
[subject subscribeNext:^(id x) {
// block调用时刻:当信号发出新值,就会调用.
NSLog(@"第一个订阅者%@",x);
}]; [subject subscribeNext:^(id x) {
// block调用时刻:当信号发出新值,就会调用.
NSLog(@"第二个订阅者%@",x);
}]; // 3.发送信号
[subject sendNext:@"1"];

替换代理:

	// 需求:
// 1.给当前控制器添加一个按钮,modal到另一个控制器界面
// 2.另一个控制器view中有个按钮,点击按钮,通知当前控制器 步骤一:在第二个控制器.h,添加一个RACSubject代替代理。
@interface TwoViewController : UIViewController @property (nonatomic, strong) RACSubject *delegateSignal; @end 步骤二:监听第二个控制器按钮点击
@implementation TwoViewController
- (IBAction)notice:(id)sender {
// 通知第一个控制器,告诉它,按钮被点了 // 通知代理
// 判断代理信号是否有值
if (self.delegateSignal) {
// 有值,才需要通知
[self.delegateSignal sendNext:nil];
}
}
@end 步骤三:在第一个控制器中,监听跳转按钮,给第二个控制器的代理信号赋值,并且监听.
@implementation OneViewController
- (IBAction)btnClick:(id)sender {
// 创建第二个控制器
TwoViewController *twoVc = [[TwoViewController alloc] init]; // 设置代理信号
twoVc.delegateSignal = [RACSubject subject]; // 订阅代理信号
[twoVc.delegateSignal subscribeNext:^(id x) {
NSLog(@"点击了通知按钮");
}]; // 跳转到第二个控制器
[self presentViewController:twoVc animated:YES completion:nil];
}
@end

三、RACRelaySubject

1. 功能

继承自RACSubject,特点是 订阅信号发送信号 没有先后顺序,而RACSubject就必须先订阅后发送。常用解决创建信号的block会带来副作用的场合,以及限制缓存值的数量

2. 使用步骤

RACRelaySubject的使用步骤和RACSubject类似,只是 订阅信号发送信号 没有先后顺序

具体使用如下:

	// RACReplaySubject:底层实现和RACSubject不一样。
// 1.调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
// 2.调用subscribeNext订阅信号,遍历保存的所有值,一个一个调用订阅者的nextBlock // 如果想当一个信号被订阅,就重复播放之前所有值,需要先发送信号,在订阅信号。
// 也就是先保存值,在订阅值。 // 1.创建信号
RACReplaySubject *replaySubject = [RACReplaySubject subject]; // 2.发送信号
[replaySubject sendNext:@1];
[replaySubject sendNext:@2]; // 3.订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一个订阅者接收到的数据%@",x);
}]; // 订阅信号
[replaySubject subscribeNext:^(id x) { NSLog(@"第二个订阅者接收到的数据%@",x);
}];

四、RACCommand

1. 功能

用于处理各种事件的类,可以把事件如何处理和数据如何传递,封装到这个类中,方便监控事件的执行过程,常用来处理网络请求场景

2. 使用步骤

  • 创建命令
initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
  • 创建signalBlock,并返回信号

  • 执行命令

- (RACSignal *)execute:(id)input

具体使用如下:

	// 二、RACCommand使用注意:
// 1.signalBlock必须要返回一个信号,不能传nil.
// 2.如果不想要传递信号,直接创建空的信号[RACSignal empty];
// 3.RACCommand中信号如果数据传递完,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中。
// 4.RACCommand需要被强引用,否则接收不到RACCommand中的信号,因此RACCommand中的信号是延迟发送的。 // 三、RACCommand设计思想:内部signalBlock为什么要返回一个信号,这个信号有什么用。
// 1.在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。
// 2.当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了。 // 四、如何拿到RACCommand中返回信号发出的数据。
// 1.RACCommand有个执行信号源executionSignals,这个是signal of signals(信号的信号),意思是信号发出的数据是信号,不是普通的类型。
// 2.订阅executionSignals就能拿到RACCommand中返回的信号,然后订阅signalBlock返回的信号,就能获取发出的值。 // 五、监听当前命令是否正在执行executing // 六、使用场景,监听按钮点击,网络请求
// 1.创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"执行命令"); // 创建空信号,必须返回信号
// return [RACSignal empty]; // 2.创建信号,用来传递数据
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"请求数据"]; // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
[subscriber sendCompleted]; return nil;
}];
}]; // 强引用命令,不要被销毁,否则接收不到数据
_conmmand = command; // 3.订阅RACCommand中的信号
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}]; // RAC高级用法
// switchToLatest:用于signal of signals,获取signal of signals发出的最新信号,也就是可以直接拿到RACCommand中的信号
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}]; // 4.监听命令是否执行完毕,默认会来一次,可以直接跳过,skip表示跳过第一次信号。
[[command.executing skip:1] subscribeNext:^(id x) { if ([x boolValue] == YES) {
// 正在执行
NSLog(@"正在执行");
}else{
// 执行完成
NSLog(@"执行完成");
}
}]; // 5.执行命令
[self.conmmand execute:@1];

五、RACMulticastConnection

1. 功能

用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理

2. 使用步骤

  • 创建信号
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
  • 创建信号
RACMulticastConnection *connect = [signal publish];
  • 订阅信号
[connect.signal subscribeNext:nextBlock]
  • 连接发送信号
[connect connect]

具体使用步骤:

	// RACMulticastConnection底层原理:
// 1.创建connect,connect.sourceSignal -> RACSignal(原始信号) connect.signal -> RACSubject
// 2.订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。
// 3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者是RACSubject
// 3.1.订阅原始信号,就会调用原始信号中的didSubscribe
// 3.2 didSubscribe,拿到订阅者调用sendNext,其实是调用RACSubject的sendNext
// 4.RACSubject的sendNext,会遍历RACSubject所有订阅者发送信号。
// 4.1 因为刚刚第二步,都是在订阅RACSubject,因此会拿到第二步所有的订阅者,调用他们的nextBlock // RACMulticastConnection:解决重复请求问题
// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) { NSLog(@"发送请求");
[subscriber sendNext:@1]; return nil;
}]; // 2.创建连接
RACMulticastConnection *connect = [signal publish]; // 3.订阅信号,
// 注意:订阅信号,也不能激活信号,只是保存订阅者到数组,必须通过连接,当调用连接,就会一次性调用所有订阅者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者一信号");
}]; [connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者二信号");
}]; // 4.连接,激活信号
[connect connect];

未完待续...

ReactiveCocoa应用篇(一)的更多相关文章

  1. ReactiveCocoa应用篇(二)

    上一篇介绍了ReactiveCocoa的常用类,已经基本满足项目中的简单应用要求,但是针对复杂的功能还需要其它的类来协同处理.ReactiveCocoa提供了强大的流程处理功能来解决复杂的问题,包括事 ...

  2. ReactiveCocoa 浅析

    转载自:http://limboy.me/ios/2013/12/27/reactivecocoa-2.html   ReactiveCocoa是Github开源的一款cocoa FRP 框架,我在之 ...

  3. ReactiveCocoa 迎接下一个更加美好的世界

    什么是ReactiveCocoa 如果你有看Github的Trending Objective-C榜单,那你肯定是见过ReactiveCocoa了.如果你在weibo上关注唐巧.onevcat等国内一 ...

  4. 说说ReactiveCocoa 2

    http://www.cocoachina.com/applenews/devnews/2014/0115/7702.html 转自无网不剩的博客     ReactiveCocoa是Github开源 ...

  5. [HMLY]11.MVVM架构

    概要 MVC架构,Model-View-Controller,如图一所示为一个典型的MVC设置. 图一:mvc Model呈现数据 View呈现用户界面 Controller调节两者之间的交互.从Mo ...

  6. TGL站长关于常见问题的回复

    问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...

  7. 最快让你上手ReactiveCocoa之基础篇

    前言 很多blog都说ReactiveCocoa好用,然后各种秀自己如何灵活运用ReactiveCocoa,但是感觉真正缺少的是一篇如何学习ReactiveCocoa的文章,这里介绍一下. 1.Rea ...

  8. 最快让你上手ReactiveCocoa之进阶篇

    前言 由于时间的问题,暂且只更新这么多了,后续还会持续更新本文<最快让你上手ReactiveCocoa之进阶篇>,目前只是简短的介绍了些RAC核心的一些方法,后续还需要加上MVVM+Rea ...

  9. ReactiveCocoa之UI篇

    前言: 上一篇讲ReactiveCocoa是函数响应式编程,并将多种事件响应的方式统一起来,使得不同的事件响应方式高度统一.同时也讲了ReactiveCocoa框架里面常见的几个概念.接下来基于那几个 ...

随机推荐

  1. Struts 框架 之 文件上传下载案例

    Struts 框架 文件上传 1. 先准备 Struts 环境 (我使用的是struts 2.3.4版本) 导jar包:

  2. 1. MongoDB 安装和启动

    1. MongoDB是一个Document Database.A record in MongoDB is a document,MongoDB documents are similar to JS ...

  3. Carbondata源码系列(一)文件生成过程

    在滴滴的两年一直在加班,人也变懒了,就很少再写博客了,最近在进行Carbondata和hive集成方面的工作,于是乎需要对Carbondata进行深入的研究. 于是新开一个系列,记录自己学习Carbo ...

  4. CJOJ 1071 【Uva】硬币问题(动态规划)

    CJOJ 1071 [Uva]硬币问题(动态规划) Description 有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多.给定非负整数S,可以选用多少个硬币,使得面值之和恰好为 ...

  5. CentOS 6.5 下安装 Redis 2.8.7(转载)

    wget http://download.redis.io/redis-stable.tar.gz tar xvzf redis-stable.tar.gz cd redis-stable make ...

  6. tag上、push上和pull 取Docker 映像

    在此之前需要拥有一个docker Hub账户,注册地址:https://hub.docker.com/. Tag.Push Docker映像 使用docker images 获取当前拥有的映像列表,其 ...

  7. 二叉树 - 建立与遍历使用Java

    二叉树的遍历(traversing binary tree)是指从根节点出发,按照某种次序依次访问二叉树中所有节点,使得每个节点仅被访问一次 前序遍历:若二叉树为空,则空操作返回null.否则先访问根 ...

  8. org.apache.hadoop.security.AccessControlException: Permission denied: user=?, access=WRITE, inode="/":hadoop:supergroup:drwxr-xr-x 异常解决

    进行如下更改:vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml[我的hadoop目录在/usr/local下,具体的是修改你的hadoop目录中的/etc/ ...

  9. Android - 基于 Speex 的高度封装语音库,0 耦合使用

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  10. 移动端https抓包那些事--初级篇

    对于刚刚进入移动安全领域的安全研究人员或者安全爱好者,在对手机APP进行渗透测试的时候会发现一个很大的问题,就是无法抓取https的流量数据包,导致渗透测试无法继续进行下去. 这次给大家介绍一些手机端 ...