关于ReactiveCocoa的比喻
“能够把信号想象成水龙头,仅仅只是里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列。不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的。除非有了接收方(subscriber),才会打开。
这样仅仅要有新的玻璃球进来,就会自己主动传送给接收方。
能够在水龙头上加一个过滤嘴(filter)。不符合的不让通过,也能够加一个修改装置,把球改变成符合自己的需求(map)。
也能够把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样仅仅要当中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。
1.RACSignal
#import <UIKit/UIKit.h>
@interface RACSignalController : UIViewController
@end
#import "RACSignalController.h"
@interface RACSignalController ()
@property (nonatomic, strong) id<RACSubscriber> subscriber;
@end
@implementation RACSignalController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"RACSignal";
/**
1. RACSiganl:信号类,一般表示将来有数据传递,只要有数据改变,信号内部接收到数据,就会马上发出数据。
信号类(RACSiganl),只是表示当数据改变时,信号内部会发出数据,它本身不具备发送信号的能力,而是交给内部一个订阅者去发出。
2. 默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
3. 如何订阅信号:调用信号RACSignal的subscribeNext就能订阅。
*/
// 核心:信号类
// 信号类作用:只要有数据改变,就会把数据包装成一个信号,传递出去。
// 只要有数据改变,就会有信号发出。
// 数据发出,并不是信号类发出。
// 1.创建信号 createSignal:didSubscribe(block)
// RACDisposable:取消订阅
// RACSubscriber:发送数据
// createSignal方法:
// 1.创建RACDynamicSignal
// 2.把didSubscribe保存到RACDynamicSignal
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// block调用时刻:当信号被订阅的时候就会调用
// block作用:描述当前信号哪些数据需要发送
// 3.发送信号
NSLog(@"调用了didSubscribe");
// 通常:传递数据出去
[subscriber sendNext:@"发送信号"];
/**
如果不在发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号
*/
[subscriber sendCompleted];
// 取消订阅方法
return [RACDisposable disposableWithBlock:^{
// 信号什么时候被取消:1.自动取消,当一个信号的订阅者被销毁的时候,就会自动取消订阅 2.主动取消
// block调用时刻:一旦一个信号,被取消订阅的时候就会调用
// block作用:当信号取消订阅,用于清空一些资源
NSLog(@"信号销毁了");
}];
}];
// 2.订阅信号
[signal subscribeNext:^(id x) {
NSLog(@"订阅信号:%@",x);
}];
//输出
//订阅信号:发送信号
//信号销毁了
/**
RACSignal底层实现
1. 创建信号,首先把didSubscribe保存到信号中,还不会触发。
2. 当信号被订阅,也就是调用signal的subscribeNext:nextBlock
2.1 subscribeNext内部会调用siganl的didSubscribe
2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中
3.0 siganl的didSubscribe中调用[subscriber sendNext:@"发送信号"];
3.1 sendNext底层其实就是执行subscriber的nextBlock
*/
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
/**
有一个全局变量保存值就不会走下面取消订阅方法:现在有问题
*/
self.subscriber = subscriber;
[subscriber sendNext:@"123"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"走销毁这个方法了");
}];
}];
//订阅信号返回RACDisposable
RACDisposable *disposable = [signal1 subscribeNext:^(id x) {
NSLog(@"接收打印的值:%@",x);
}];
// 默认一个信号发送数据完毕们就会主动取消订阅.
// 只要订阅者在,就不会自动取消信号订阅
// 手动取消订阅者
[disposable dispose];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
2.RACSubscriber
#import <UIKit/UIKit.h>
@interface RACSubscriberController : UIViewController
@end
#import "RACSubscriberController.h"
#import "RedView.h"
@interface RACSubscriberController ()
@end
@implementation RACSubscriberController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"RACSubscriber";
/**
1. RACSubscriber: 表示订阅者的意思,用于发送信号,这是一个协议,不是一个类,只要遵守这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助他发送数据。
2. RACDisposable:用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。
使用场景:不想监听某个信号时,可以通过它主动取消订阅信号。
3. RACSubject:RACSubject:信号提供者,自己可以充当信号,又能发送信号。
使用场景:通常用来代替代理,有了它,就不必要定义代理了。
4. RACReplaySubject:重复提供信号类,RACSubject的子类。
RACReplaySubject与RACSubject区别:
RACReplaySubject可以先发送信号,在订阅信号,RACSubject就不可以。
使用场景一:如果一个信号每被订阅一次,就需要把之前的值重复发送一遍,使用重复提供信号类。
使用场景二:可以设置capacity数量来限制缓存的value的数量,即只缓充最新的几个值。
*/
// RACSubject使用
[self RACSubjectUse];
// RACReplaySubject使用
[self RACReplaySubjectUse];
// RACSubject替换代理使用
[self RACSubjectReplaceAgent];
}
#pragma mark - RACSubjectUse
- (void)RACSubjectUse {
// RACSubject使用步骤
// 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
// 2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.发送信号 sendNext:(id)value
// 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.订阅信号
[subject subscribeNext:^(id x) {
//当信号发出新值,就会调用.
NSLog(@"第一个订阅者%@",x);
}];
[subject subscribeNext:^(id x) {
NSLog(@"第二个订阅者%@",x);
}];
// 3.发送信号
[subject sendNext:@"123456"];
// 4.发送信号完成,内部会自动取消订阅者
[subject sendCompleted];
// 输出:
// 第一个订阅者123456
// 第二个订阅者123456
}
#pragma mark - RACReplaySubjectUse
-(void)RACReplaySubjectUse {
// RACReplaySubject使用步骤:
// 1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
// 2.可以先订阅信号,也可以先发送信号。
// 2.1 订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 2.2 发送信号 sendNext:(id)value
// 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);
}];
// 输出:
// 第一个订阅者接收到的数据1
// 第一个订阅者接收到的数据2
// 第二个订阅者接收到的数据1
// 第二个订阅者接收到的数据2
}
#pragma mark - RACSubject替换代理
- (void)RACSubjectReplaceAgent {
RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
redView.frame = CGRectMake(0, 64, 300, 200);
redView.center = self.view.center;
[redView.btnClickSignal subscribeNext:^(id x) {
NSLog(@"---%@--",x);
}];
[self.view addSubview:redView];
}
@end
3.RAC集合
#import <UIKit/UIKit.h>
@interface RACSetViewController : UIViewController
@end
#import "RACSetViewController.h"
#import "Flag.h"
@interface RACSetViewController ()
@end
@implementation RACSetViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self tuple];
[self array];
[self dictionary];
[self initWithDictionary];
}
#pragma mark- RACTuple数组
- (void)tuple {
/**
RACTuple:元组类,类似NSArray,用来包装值.
*/
//元组
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"345",@1]];
NSString *first = tuple[0];
NSLog(@"%@",first);
//输出:
//123
}
#pragma mark- RACSequence数组
- (void)array {
// 数组
NSArray *arr = @[@"213",@"321",@1];
//RAC 集合
RACSequence *sequence = arr.rac_sequence;
// 把集合转换成信号
RACSignal *signal = sequence.signal;
//订阅集合信号,内部会自动遍历所有的元素发出来
[signal subscribeNext:^(id x) {
NSLog(@"遍历数组%@",x);
}];
//输出:
/**
遍历数组213
遍历数组321
遍历数组1
*/
//高级写法
[arr.rac_sequence.signal subscribeNext:^(id x) {
NSLog(@"高级写法遍历数组打印%@",x);
}];
//输出:
/**
高级写法遍历数组打印213
高级写法遍历数组打印321
高级写法遍历数组打印1
*/
}
#pragma mark- RACTuple数组
- (void)dictionary {
// 字典
NSDictionary *dict = @{@"sex":@"女",@"name":@"苍老师",@"age":@18};
//转换成集合
[dict.rac_sequence.signal subscribeNext:^(RACTuple *x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack:用来解析元组
// 宏里面的参数,传需要解析出来的变量名
//= 右边,放需要解析的元组
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@",key,value);
}];
//输出:
/**
sex 女
name 苍老师
age 18
*/
}
#pragma mark- 字典转模型
- (void)initWithDictionary {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:filePath];
// NSMutableArray *arr = [NSMutableArray array];
// // rac_sequence注意点:调用subscribeNext,并不会马上执行nextBlock,而是会等一会。
// [dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *x) {
// Flag *flag = [Flag flagWithDict:x];
// [arr addObject:flag];
// }];
//高级用法
// map:映射的意思,目的:把原始值value映射成一个新值
// array: 把集合转换成数组
// 底层实现:当信号被订阅,会遍历集合中的原始值,映射成新值,并且保存到新的数组里。
NSArray *arr = [[dictArr.rac_sequence map:^id(NSDictionary *value) {
return [Flag flagWithDict:value];
}] array];
NSLog(@"%@",arr);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
4.RACMulticastConnection
#import <UIKit/UIKit.h>
@interface RACMulticastConnectionController : UIViewController
@end
#import "RACMulticastConnectionController.h"
@interface RACMulticastConnectionController ()
@end
@implementation RACMulticastConnectionController
- (void)viewDidLoad {
[super viewDidLoad];
/**
RACMulticastConnection:用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。
使用注意:RACMulticastConnection通过RACSignal的-publish或者-muticast:方法创建.
*/
[self RACMulticastConnection];
}
- (void)RACMulticastConnection {
//RACMulticastConnection简单使用:
// RACMulticastConnection使用步骤:
// 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// 2.创建连接 RACMulticastConnection *connect = [signal publish];
// 3.订阅信号,注意:订阅的不在是之前的信号,而是连接的信号。 [connect.signal subscribeNext:nextBlock]
// 4.连接 [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<RACSubscriber> subscriber) {
NSLog(@"发送请求");
[subscriber sendNext:@"1"];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 2.订阅信号
[signal subscribeNext:^(id x) {
NSLog(@"接收数据");
}];
[signal subscribeNext:^(id x) {
NSLog(@"接收数据");
}];
// 3.运行结果,会执行两遍发送请求,也就是每次订阅都会发送一次请求
// RACMulticastConnection:解决重复请求问题
// 1.创建信号
RACSignal *connectionSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"发送请求--");
[subscriber sendNext:@1];
return [RACDisposable disposableWithBlock:^{
}];
}];
//2.创建连接
RACMulticastConnection *connect = [connectionSignal publish];
//3.订阅信号
// 注意:订阅信号,也不能激活信号,只是保存订阅者到数组,必须通过连接,当调用连接,就会一次性调用所有订阅者的sendNext:
[connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者一信号--");
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者二信号--");
}];
//4.连接,激活信号
[connect connect];
//输出:
/**
发送请求--
订阅者一信号--
订阅者二信号--
*/
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
5.RACCommand
#import <UIKit/UIKit.h>
@interface RACCommandController : UIViewController
@end
#import "RACCommandController.h"
@interface RACCommandController ()
@property (nonatomic, strong) RACCommand *command;
@end
@implementation RACCommandController
- (void)viewDidLoad {
[super viewDidLoad];
/**
RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。
使用场景:监听按钮点击,网络请求
*/
[self RACCommandUse];
[self switchToLatest];
[self commandData];
}
- (void)RACCommandUse {
// 一、RACCommand使用步骤:
// 1.创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
// 2.在signalBlock中,创建RACSignal,并且作为signalBlock的返回值
// 3.执行命令 - (RACSignal *)execute:(id)input
// 二、RACCommand使用注意:
// 1.signalBlock必须要返回一个信号,不能传nil.
// 2.如果不想要传递信号,直接创建空的信号[RACSignal empty];
// 3.RACCommand中信号如果数据传递完,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中。
// 三、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<RACSubscriber> subscriber) {
[subscriber sendNext:@"请求数据"];
// 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"数据销毁");
}];
}];
}];
// 强引用命令,不要被销毁,否则接收不到数据
_command = command;
// 监听事件有没有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) { // 当前正在执行
NSLog(@"当前正在执行");
}else{
// 执行完成/没有执行
NSLog(@"执行完成/没有执行");
}
}];
// 获取信号中信号发送的最新信号
[self.command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 执行命令
//[self.command execute:@1];
}
// RAC高级用法
- (void)switchToLatest {
//创建信号中信号
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
// 订阅信号
// [signalOfSignals subscribeNext:^(RACSignal *x) {
// [x subscribeNext:^(id x) {
// NSLog(@"%@",x);
// }];
// }];
// switchToLatest:获取信号中信号发送的最新信号
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 发送信号
[signalOfSignals sendNext:signalA];
[signalA sendNext:@1];
[signalB sendNext:@"BB"];
[signalA sendNext:@"11"];
}
- (void)commandData
{
// RACCommand:处理事件
// RACCommand:不能返回一个空的信号
// 1.创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
// input:执行命令传入参数
// Block调用:执行命令的时候就会调用
NSLog(@"input-%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送数据
[subscriber sendNext:@"执行命令产生的数据"];
return nil;
}];
}];
// 如何拿到执行命令中产生的数据
// 订阅命令内部的信号
// 1.方式一:直接订阅执行命令返回的信号
// 2.方式二:
// 2.执行命令
RACSignal *signal = [command execute:@1];
// 3.订阅信号
[signal subscribeNext:^(id x) {
NSLog(@"x-%@",x);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
6.RAC常用方法--常见宏
@interface RACMethodUseViewController : UIViewController
@end
#import "RACMethodUseViewController.h"
#import "RedView.h"
@interface RACMethodUseViewController ()
@end
@implementation RACMethodUseViewController
- (void)viewDidLoad {
[super viewDidLoad];
#pragma mark -常见的五个宏
////常见的五个宏
//使用宏定义要单独导入 #import <RACEXTScope.h>
// 1:
/*
RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定信号
只要文本框文字改变,就会修改label的文字
RAC(self.labelView,text) = _textField.rac_textSignal;
*/
// 2:
/*
RACObserve(self, name):监听某个对象的某个属性,返回的是信号。
[RACObserve(self.view, center) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
*/
//当RACObserve放在block里面使用时一定要加上weakify,不管里面有没有使用到self;否则会内存泄漏,因为RACObserve宏里面就有一个self
/*
@weakify(self);
RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) {
Avoids a retain cycle because of RACObserve implicitly referencing self
@strongify(self);
return RACObserve(arrayController, items);
}];
*/
//3:
//@weakify(Obj)和@strongify(Obj),一般两个都是配套使用,在主头文件(ReactiveCocoa.h)中并没有导入,需要自己手动导入,RACEXTScope.h才可以使用。但是每次导入都非常麻烦,只需要在主头文件自己导入就好了
// 4:
/*
RACTuplePack:把数据包装成RACTuple(元组类)
把参数中的数据包装成元组
RACTuple *tuple = RACTuplePack(@10,@20);
*/
//5:
/*
RACTupleUnpack:把RACTuple(元组类)解包成对应的数据
把参数中的数据包装成元组
RACTuple *tuple = RACTuplePack(@"xmg",@20);
解包元组,会把元组的值,按顺序给参数里面的变量赋值
name = @"xmg" age = @20
RACTupleUnpack(NSString *name,NSNumber *age) = tuple;
*/
[self initView];
}
- (void)initView {
self.navigationItem.title = @"RAC常用方法";
self.view.backgroundColor = [UIColor whiteColor];
#pragma mark -监听按钮的点击事件
// 1.监听按钮的点击事件
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(100, 100, 80, 40);
[button setTitle:@"点击事件" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor redColor]];
[self.view addSubview:button];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按钮被点击了");
}];
#pragma mark -代理的使用
// 2.代理的使用
// 2.1 只要传值,就必须使用RACSubject
RedView *redView = [[[NSBundle mainBundle] loadNibNamed:@"RedView" owner:nil options:nil] lastObject];
redView.frame = CGRectMake(0, 140, self.view.bounds.size.width, 200);
[self.view addSubview:redView];
[redView.btnClickSignal subscribeNext:^(id x) {
NSLog(@"---点击按钮了,触发了事件");
}];
// 2.2把控制器调用didReceiveMemoryWarning转换成信号
// rac_signalForSelector:监听某对象有没有调用某方法
[[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {
NSLog(@"控制器调用didReceiveMemoryWarning");
}];
#pragma mark -KVO
// 3.KVO
// 把监听redV的center属性改变转换成信号,只要值改变就会发送信号
// observer:可以传入nil
[[redView rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"center:%@",x);
}];
#pragma mark -代替通知
// 4.代替通知
UITextField *textfield = [[UITextField alloc] initWithFrame:CGRectMake(100, 340, 150, 40)];
textfield.placeholder = @"监听键盘的弹起";
textfield.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:textfield];
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"监听键盘的高度:%@",x);
}];
#pragma mark -监听文本框的文字改变
// 5.监听文本框的文字改变
[textfield.rac_textSignal subscribeNext:^(id x) {
NSLog(@"输入框中文字改变了---%@",x);
}];
#pragma mark -处理多个请求,都返回结果的时候,统一做处理.
// 6.处理多个请求,都返回结果的时候,统一做处理.
RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求1
[subscriber sendNext:@"发送请求1"];
return nil;
}];
RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求2
[subscriber sendNext:@"发送请求2"];
return nil;
}];
// 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
[self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
}
// 更新UI
- (void)updateUIWithR1:(id)data r2:(id)data1
{
NSLog(@"更新UI%@ %@",data,data1);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
7.RAC操作方法一
#import <UIKit/UIKit.h>
@interface RACOperationMethodController : UIViewController
@end
//1.ReactiveCocoa常见操作方法介绍。
/**
1.1 ReactiveCocoa操作须知
所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中,而RACSignal继承RACStream。
1.2 ReactiveCocoa操作思想
运用的是Hook(钩子)思想,Hook是一种用于改变API(应用程序编程接口:方法)执行结果的技术.
Hook用处:截获API调用的技术。
Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出。
RAC开发方式:RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。
列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。
1.3 ReactiveCocoa核心方法bind
ReactiveCocoa操作的核心方法是bind(绑定),给RAC中的信号进行绑定,只要信号一发送数据,就能监听到,从而把发送数据改成自己想要的数据。
在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.
bind方法简单介绍和使用。
*/
/**
// 假设想监听文本框的内容,并且在每次输出结果的时候,都在文本框的内容拼接一段文字“输出:”
// 方式一:在返回结果后,拼接。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"输出:%@",x);
}];
// 方式二:在返回结果前,拼接,使用RAC中bind方法做处理。
// bind方法参数:需要传入一个返回值是RACStreamBindBlock的block参数
// RACStreamBindBlock是一个block的类型,返回值是信号,参数(value,stop),因此参数的block返回值也是一个block。
// RACStreamBindBlock:
// 参数一(value):表示接收到信号的原始值,还没做处理
// 参数二(*stop):用来控制绑定Block,如果*stop = yes,那么就会结束绑定。
// 返回值:信号,做好处理,在通过这个信号返回出去,一般使用RACReturnSignal,需要手动导入头文件RACReturnSignal.h。
// bind方法使用步骤:
// 1.传入一个返回值RACStreamBindBlock的block。
// 2.描述一个RACStreamBindBlock类型的bindBlock作为block的返回值。
// 3.描述一个返回结果的信号,作为bindBlock的返回值。
// 注意:在bindBlock中做信号结果的处理。
// 底层实现:
// 1.源信号调用bind,会重新创建一个绑定信号。
// 2.当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock。
// 3.当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
// 4.调用bindingBlock(value,stop),会返回一个内容处理完成的信号(RACReturnSignal)。
// 5.订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
// 注意:不同订阅者,保存不同的nextBlock,看源码的时候,一定要看清楚订阅者是哪个。
// 这里需要手动导入#import <ReactiveCocoa/RACReturnSignal.h>,才能使用RACReturnSignal。
[[_textField.rac_textSignal bind:^RACStreamBindBlock{
// 什么时候调用:
// block作用:表示绑定了一个信号.
return ^RACStream *(id value, BOOL *stop){
// 什么时候调用block:当信号有新的值发出,就会来到这个block。
// block作用:做返回值的处理
// 做好处理,通过信号返回出去.
return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
};
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
*/
#import "RACOperationMethodController.h"
#import <RACReturnSignal.h>
@interface RACOperationMethodController ()
@property (strong, nonatomic) UITextField *textField;
@end
@implementation RACOperationMethodController
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self flattenMap];
[self map];
[self flatternMapWithMap];
[self RACOperationMethodCombination];
}
- (void)initView {
self.navigationItem.title = @"RAC 操作方法一";
self.view.backgroundColor = [UIColor whiteColor];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
_textField.center = self.view.center;
_textField.placeholder = @"请输入内容";
[self.view addSubview:_textField];
}
//flattenMap简单使用
// 监听文本框的内容改变,把结构重新映射成一个新值.
// flattenMap作用:把源信号的内容映射成一个新的信号,信号可以是任意类型。
- (void)flattenMap {
// flattenMap使用步骤:
// 1.传入一个block,block类型是返回值RACStream,参数value
// 2.参数value就是源信号的内容,拿到源信号的内容做处理
// 3.包装成RACReturnSignal信号,返回出去。
// flattenMap底层实现:
// 0.flattenMap内部调用bind方法实现的,flattenMap中block的返回值,会作为bind中bindBlock的返回值。
// 1.当订阅绑定信号,就会生成bindBlock。
// 2.当源信号发送内容,就会调用bindBlock(value, *stop)
// 3.调用bindBlock,内部就会调用flattenMap的block,flattenMap的block作用:就是把处理好的数据包装成信号。
// 4.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
// 5.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
[[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
// block什么时候 : 源信号发出的时候,就会调用这个block。
// block作用 : 改变源信号的内容。
// 返回值:绑定信号的内容.
return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
}] subscribeNext:^(id x) {
// 订阅绑定信号,每当源信号发送内容,做完处理,就会调用这个block。
NSLog(@"输出:flattenMap%@",x);
}];
}
- (void)map {
//Map简单使用:
// 监听文本框的内容改变,把结构重新映射成一个新值.
// Map作用:把源信号的值映射成一个新的值
// Map使用步骤:
// 1.传入一个block,类型是返回对象,参数是value
// 2.value就是源信号的内容,直接拿到源信号的内容做处理
// 3.把处理好的内容,直接返回就好了,不用包装成信号,返回的值,就是映射的值。
// Map底层实现:
// 0.Map底层其实是调用flatternMap,Map中block中的返回的值会作为flatternMap中block中的值。
// 1.当订阅绑定信号,就会生成bindBlock。
// 3.当源信号发送内容,就会调用bindBlock(value, *stop)
// 4.调用bindBlock,内部就会调用flattenMap的block
// 5.flattenMap的block内部会调用Map中的block,把Map中的block返回的内容包装成返回的信号。
// 5.返回的信号最终会作为bindBlock中的返回信号,当做bindBlock的返回信号。
// 6.订阅bindBlock的返回信号,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
[[_textField.rac_textSignal map:^id(id value) {
// 当源信号发出,就会调用这个block,修改源信号的内容
// 返回值:就是处理完源信号的内容。
return [NSString stringWithFormat:@"输出:%@",value];
}] subscribeNext:^(id x) {
NSLog(@"map输出%@",x);
}];
}
- (void)flatternMapWithMap {
/**
FlatternMap和Map的区别
1.FlatternMap中的Block返回信号。
2.Map中的Block返回对象。
3.开发中,如果信号发出的值不是信号,映射一般使用Map
4.开发中,如果信号发出的值是信号,映射一般使用FlatternMap。
总结:signalOfsignals用FlatternMap。
*/
//创建信号中的信号
RACSubject *signalOfsignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[signalOfsignals flattenMap:^RACStream *(id value) {
//当signalOfsignals的signals发出信号才会调用
return value;
}] subscribeNext:^(id x) {
// 只有signalOfsignals的signal发出信号才会调用,因为内部订阅了bindBlock中返回的信号,也就是flattenMap返回的信号。
// 也就是flattenMap返回的信号发出内容,才会调用。
NSLog(@"%@aaa",x);
}];
// 信号的信号发送信号
[signalOfsignals sendNext:signal];
// 信号发送内容
[signal sendNext:@1];
}
//RAC 操作之组合
- (void)RACOperationMethodCombination {
//一.concat:按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
[subscriber sendCompleted];
return nil;
}];
// 把signalA拼接到signalB后,signalA发送完成,signalB才会被激活。
RACSignal *concatSignal = [signalA concat:signalB];
// 以后只需要面对拼接信号开发。
// 订阅拼接的信号,不需要单独订阅signalA,signalB
// 内部会自动订阅。
// 注意:第一个信号必须发送完成,第二个信号才会被激活
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// concat底层实现:
// 1.当拼接信号被订阅,就会调用拼接信号的didSubscribe
// 2.didSubscribe中,会先订阅第一个源信号(signalA)
// 3.会执行第一个源信号(signalA)的didSubscribe
// 4.第一个源信号(signalA)didSubscribe中发送值,就会调用第一个源信号(signalA)订阅者的nextBlock,通过拼接信号的订阅者把值发送出来.
// 5.第一个源信号(signalA)didSubscribe中发送完成,就会调用第一个源信号(signalA)订阅者的completedBlock,订阅第二个源信号(signalB)这时候才激活(signalB)。
// 6.订阅第二个源信号(signalB),执行第二个源信号(signalB)的didSubscribe
// 7.第二个源信号(signalA)didSubscribe中发送值,就会通过拼接信号的订阅者把值发送出来.
//二.then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号。
// then:用于连接两个信号,当第一个信号完成,才会连接then返回的信号
// 注意使用then,之前信号的值会被忽略掉.
// 底层实现:1、先过滤掉之前的信号发出的值。2.使用concat连接then返回的信号
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
}] subscribeNext:^(id x) {
// 只能接收到第二个信号的值,也就是then返回信号的值
NSLog(@"%@",x);
}];
//三.merge:把多个信号合并为一个信号,任何一个信号有新值的时候就会调用.
//merge: 把多个信号合并成一个信号
//创建多个信号
RACSignal *signalC = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@3];
return [RACDisposable disposableWithBlock:^{
NSLog(@"信号释放了");
}];
}];
RACSignal *signalD = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@4];
return [RACDisposable disposableWithBlock:^{
NSLog(@"信号释放了");
}];
}];
//合并信号.任何一个信号发送数据,都能监听到
RACSignal *mergeSignal = [signalC merge:signalD];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"合并信号,任何一个数据发送数据,都能监听到%@",x);
}];
// 底层实现:
// 1.合并信号被订阅的时候,就会遍历所有信号,并且发出这些信号。
// 2.每发出一个信号,这个信号就会被订阅
// 3.也就是合并信号一被订阅,就会订阅里面所有的信号。
// 4.只要有一个信号被发出就会被监听。
//四.zipWith:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。
RACSignal *signalE = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalF = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 压缩信号A,信号B
RACSignal *zipSignal = [signalE zipWith:signalF];
[zipSignal subscribeNext:^(id x) {
NSLog(@"压缩的信号%@",x);
}];
// 底层实现:
// 1.定义压缩信号,内部就会自动订阅signalA,signalB
// 2.每当signalA或者signalB发出信号,就会判断signalA,signalB有没有发出个信号,有就会把最近发出的信号都包装成元组发出。
//第五:combineLatest:将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号.
RACSignal *signalG = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalH = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
// 把两个信号组合成一个信号,跟zip一样,没什么区别
RACSignal *combineSignal = [signalG combineLatestWith:signalH];
[combineSignal subscribeNext:^(id x) {
NSLog(@"把两个信号组合成一个信号%@",x);
}];
// 底层实现:
// 1.当组合信号被订阅,内部会自动订阅signalA,signalB,必须两个信号都发出内容,才会被触发。
// 2.并且把两个信号组合成元组发出。
//第六:reduce聚合:用于信号发出的内容是元组,把信号发出元组的值聚合成一个值
RACSignal *signalL = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@5];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *signalM = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@6];
return [RACDisposable disposableWithBlock:^{
}];
}];
RACSignal *reduceSignal = [RACSignal combineLatest:@[signalL,signalM] reduce:^id(NSNumber *num1, NSNumber *num2){
return [NSString stringWithFormat:@"reduce聚合%@ %@",num1,num2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// // 底层实现:
// 1.订阅聚合信号,每次有内容发出,就会执行reduceblcok,把信号内容转换成reduceblcok返回的值。
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
8.RAC操作方法二
#import <UIKit/UIKit.h>
@interface RACOperationMethodFilteringVC : UIViewController
@end
#import "RACOperationMethodFilteringVC.h"
@interface RACOperationMethodFilteringVC ()
@property (strong, nonatomic) UITextField *textField;
@end
@implementation RACOperationMethodFilteringVC
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self filter];
[self ignore];
[self ignoreValues];
[self takeUntilBlock];
[self distinctUntilChanged];
[self take];
[self takeLast];
[self takeUntil];
[self skip];
[self switchToLatest];
}
- (void)initView {
self.navigationItem.title = @"RAC操作方法二";
self.view.backgroundColor = [UIColor whiteColor];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
_textField.center = self.view.center;
_textField.borderStyle = UITextBorderStyleBezel;
_textField.placeholder = @"请输入内容";
[self.view addSubview:_textField];
}
//过滤信号,使用它可以获取满足条件的信号.
- (void)filter {
//filter 过滤
//每次信号发出,会先执行过滤条件判断
[_textField.rac_textSignal filter:^BOOL(NSString *value) {
return value.length > 3;
}];
}
//ignore:忽略完某些值的信号.
- (void)ignore {
// 内部调用filter过滤,忽略掉ignore的值
[[_textField.rac_textSignal ignore:@"1"] subscribeNext:^(id x) {
NSLog(@"ignore%@",x);
}];
}
//ignoreValues 这个比较极端,忽略所有值,只关心Signal结束,也就是只取Comletion和Error两个消息,中间所有值都丢弃
- (void)ignoreValues {
RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"15"];
[subscriber sendNext:@"wujy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"执行清理");
}];
}];
[[signal ignoreValues] subscribeNext:^(id x) {
//它是没机会执行 因为ignoreValues已经忽略所有的next值
NSLog(@"ignoreValues当前值:%@",x);
} error:^(NSError *error) {
NSLog(@"ignoreValues error");
} completed:^{
NSLog(@"ignoreValues completed");
}];
}
//distinctUntilChanged:当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。
- (void)distinctUntilChanged {
// 过滤,当上一次和当前的值不一样,就会发出内容。
// 在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
[[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"distinctUntilChanged%@",x);
}];
}
//take:从开始一共取N次的信号
- (void)take {
//1.创建信号
RACSubject *signal = [RACSubject subject];
//2.处理信号,订阅信号
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"take:%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
}
//takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号.
- (void)takeLast {
//1.创建信号
RACSubject *signal = [RACSubject subject];
//2.处理信号,订阅信号
[[signal takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//3.发送信号
[signal sendNext:@1];
[signal sendNext:@332];
[signal sendNext:@333];
[signal sendCompleted];
}
//takeUntil:(RACSignal *):获取信号直到执行完这个信号
- (void)takeUntil {
// 监听文本框的改变,知道当前对象被销毁
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
}
//takeUntilBlock 对于每个next值,运行block,当block返回YES时停止取值
- (void)takeUntilBlock {
RACSignal *signal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"15"];
[subscriber sendNext:@"wujy"];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
NSLog(@"执行清理");
}];
}];
[[signal takeUntilBlock:^BOOL(NSString *x) {
if ([x isEqualToString:@"15"]) {
return YES;
}
return NO;
}] subscribeNext:^(id x) {
NSLog(@"takeUntilBlock 获取的值:%@",x);
}];
// 输出
// takeUntilBlock 获取的值:1
// takeUntilBlock 获取的值:3
}
//skip:(NSUInteger):跳过几个信号,不接受。
- (void)skip {
[[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {
NSLog(@"跳过几个信号不接收%@",x);
}];
}
//switchToLatest:用于signalOfSignals(信号的信号),有时候信号也会发出信号,会在signalOfSignals中,获取signalOfSignals发送的最新信号。
- (void)switchToLatest {
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[signalOfSignals sendNext:signal];
// 获取信号中信号最近发出信号,订阅最近发出的信号。
// 注意switchToLatest:只能用于信号中的信号
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"获取信号中信号最近发出信号,订阅最近发出的信号%@",x);
}];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
9.RAC操作方法三
#import <UIKit/UIKit.h>
@interface RACOperationOrderController : UIViewController
@end
#import "RACOperationOrderController.h"
@interface RACOperationOrderController ()
@property (nonatomic, strong) RACSubject *signal;
@end
@implementation RACOperationOrderController
- (void)viewDidLoad {
[super viewDidLoad];
[self initView];
[self doNext];
[self deliverOn];
[self timeout];
[self interval];
[self delay];
[self retry];
[self replay];
[self throttle];
}
- (void)initView {
self.navigationItem.title = @"RAC操作方法三";
self.view.backgroundColor = [UIColor whiteColor];
}
//ReactiveCocoa操作方法之秩序。
- (void)doNext {
//doNext: 执行Next之前,会先执行这个Block
//doCompleted: 执行sendCompleted之前,会先执行这个Block
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] doNext:^(id x) {
// 执行[subscriber sendNext:@1];之前会调用这个Block
NSLog(@"doNext");
}] doCompleted:^{
// 执行[subscriber sendCompleted];之前会调用这个Block
NSLog(@"doCompleted");
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
//ReactiveCocoa操作方法之线程。
- (void)deliverOn {
//deliverOn: 内容传递切换到制定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
//subscribeOn: 内容传递和副作用都会切换到制定线程中。
}
//ReactiveCocoa操作方法之时间。
- (void)timeout {
//timeout:超时,可以让一个信号在一定的时间后,自动报错。
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
return nil;
}] timeout:1 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
// 1秒后会自动调用
NSLog(@"%@",error);
}];
}
//interval 定时:每隔一段时间发出信号
- (void)interval {
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
}
//delay 延迟发送next
- (void)delay {
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
// ReactiveCocoa操作方法之重复。
- (void)retry {
//retry重试 :只要失败,就会重新执行创建信号中的block,直到成功.
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (i == 10) {
[subscriber sendNext:@1];
}else{
NSLog(@"接收到错误");
[subscriber sendError:nil];
}
i++;
return nil;
}] retry] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
}];
}
//replay重放:当一个信号被多次订阅,反复播放内容
- (void)replay {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一个订阅者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二个订阅者%@",x);
}];
}
- (void)throttle {
RACSubject *signal = [RACSubject subject];
_signal = signal;
// 节流,在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
网友评论