RAC使用容易忽略掉一些细节,从而出现内存泄漏,注意⚠️
ReactiveCocoa结合了几种编程风格:
函数式编程(Functional Programming)
响应式编程(Reactive Programming)
ReactiveCocoa被描述为函数响应式编程(FRP)框架
一、常见的类学习:
1、RACSignal
/*RACSignal:有数据产生的时候就使用
使用步骤:1、创建信号;2、订阅信号;3、发送信号;
*/
//1、创建信号(冷信号)
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//有返回值的block,_Nullable可为空
/*
这个block叫didSubscribe
调用:只要一个信号被订阅就会调用
作用:发送数据
*/
NSLog(@"信号被订阅");
//3、发送数据
[subscriber sendNext:@1];
return nil;
}];
//2、订阅信号(热信号)
[signal subscribeNext:^(id _Nullable x) {
/*
nextBlock
调用:只要订阅者发送数据就会调用
作用:接收数据,处理数据,展示到UI上
*/
//x:信号发送的内容
NSLog(@"-----%@",x);
}];
/*
只要订阅者调用sendNext,就会执行nextBlock
只要订阅RACDynamicSignal类型的信号,就会执行didSubscribe
前提条件:一定要是RACDynamicSignal,不同类型的信号,处理订阅的事情不一样
*/
2、RACSubscriber
表示订阅者的意思,用于发送信号,这是一个协议,不是一个类,只要遵守这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助他发送数据。
3、RACDisposable
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//用属性保存下来,防止subscriber自动销毁
_subscriber = subscriber;
[subscriber sendNext:@123];
return [RACDisposable disposableWithBlock:^{
/*
只要订阅取消就会来到这里
作用:清空资源
*/
NSLog(@"信号被取消订阅了");
}];
}];
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"----------%@",x);
}];
/*
默认一个信号发送完毕就会取消信号订阅
但是只要订阅者在,就不会自动取消信号订阅
*/
//手动取消订阅信号
[disposable dispose];
4、RACSubject (代替代理)
/*
RACSubject:信号提供者,自己可以充当信号,又能发送信号
想要某个类拥有多个类的功能,就可以继承一个类,再遵守协议,这叫做面向协议的思想
*/
//1、创建信号
RACSubject *subject = [RACSubject subject];
//2、订阅信号
//RACSubject:仅仅保存订阅者
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"1、接收到数据:%@",x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"2、接收到数据:%@",x);
}];
//3、发送数据
[subject sendNext:@123];
//底层实现:遍历订阅者,调用nextBlock
5、RACReplaySubject (可以先发送信号再订阅)
//1、创建信号
RACReplaySubject *replaySubject = [RACReplaySubject subject];
//3、发送信号
[replaySubject sendNext:@1111];
//2、订阅信号
[replaySubject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//遍历所有的值,拿到当前订阅者去发送数据
/*
RACReplaySubject发送数据:
1、保存值
2、遍历所有的订阅者,发送数据
RACReplaySubject可以先发送信号再订阅
*/
6、RACMulticastConnection
用法:当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,也就是请求数据的block,造成副作用,可以使用这个类处理。
使用注意:RACMulticastConnection通过RACSignal的-publish或者-muticast:方法创建.
eg:信号被多次订阅的时候,会重复请求数据
代码:
RACSignal *s0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---请求数据");
[subscriber sendNext:@"得到的数据"];
return nil;
}];
[s0 subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[s0 subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---请求数据
2017-07-28 10:17:37.837 RAC_learning[1180:38354] 得到的数据
2017-07-28 10:17:37.837 RAC_learning[1180:38354] ---请求数据
2017-07-28 10:17:37.838 RAC_learning[1180:38354] 得到的数据
这样导致了多次请求数据,所以用RACMulticastConnection可以实现不论多少次订阅,只请求一次数据
eg:用RACMulticastConnection
//1、创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"---请求数据");
[subscriber sendNext:@"得到的数据"];
return nil;
}];
//2、把信号转换成连接类
RACMulticastConnection *connection = signal.publish;
//或者
//RACMulticastConnection *connection = [signal multicast:[RACReplaySubject subject]];
//3、订阅信号
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第一次获取:%@",x);
}];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"第二次获取:%@",x);
}];
//4、连接
[connection connect];
输出
2017-07-28 10:22:09.098 RAC_learning[1243:41311] ---请求数据
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第一次获取:得到的数据
2017-07-28 10:22:09.099 RAC_learning[1243:41311] 第二次获取:得到的数据
7、RACCommand
RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。
使用场景:监听按钮点击,网络请求
(1)==RACCommand==
//1、创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//得到执行命令传入参数
NSLog(@"得到执行命令传入参数input = %@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"请求到的数据"];
return nil;
}];
}];
/*
如何拿到执行命令中产生的数据
订阅命令内部的信号
1.方式一:直接订阅执行命令返回的信号(execute方法返回RACSignal)
2.方式二:executionSignals:获取信号源
*/
//2、执行命令
//方式一:直接订阅执行命令返回的信号(execute方法返回RACSignal) 必须在执行命令之后执行
/*
RACSignal *signal = [command execute:@1];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
*/
//方式二:executionSignals:获取信号源 必须在执行命令之前执行
/*
[command.executionSignals subscribeNext:^(RACSignal *x) {
//这里获取到的是RACSignal
[x subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
*/
//switchToLatest:得到信号源中最新的信号
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[command execute:@1];
(2)==switchToLatest==:得到信号源中最新的信号
// 创建信号中信号
RACSubject *signalOfSignals = [RACSubject subject];
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
//只会得到最新的发送的信号signalB
[signalOfSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 发送信号
[signalOfSignals sendNext:signalA];
[signalOfSignals sendNext:signalB];
[signalA sendNext:@1];
[signalB sendNext:@"BB"];
[signalA sendNext:@"11"];
(3)==executing==:监听事件有没有完成
// 1.创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@",input);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送数据
[subscriber sendNext:@"执行命令产生的数据"];
// 主动发送完成,这样才会监听到发送完成的时候
[subscriber sendCompleted];
return nil;
}];
}];
// 监听事件有没有完成
[command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) {
// 当前正在执行
NSLog(@"当前正在执行");
}else{
// 执行完成/没有执行
NSLog(@"执行完成/没有执行");
}
}];
// 2.执行命令
[command execute:@1];
二、集合类学习
1、RACTuple
(1)当作数组用
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123",@"456",@789]];
NSString *string = tuple[0];
NSLog(@"%@",string);
2、RACSequence
(1)当作数组用
NSArray *array = @[@"123",@"456",@789];
//数组转集合
RACSequence *sequence = array.rac_sequence;
//集合转信号
RACSignal *signal = sequence.signal;
//遍历
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//简单写法------------
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
(2)当集合用
NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
// NSString *key = x[0];
// NSString *value = x[1];
// NSLog(@"%@ %@",key,value);
// RACTupleUnpack:用来解析元组
// 宏里面的参数,传需要解析出来的变量名
// = 右边,放需要解析的元组
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@", key, value);
}];
NSArray *dictArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"flags.plist" ofType:nil]];
NSMutableArray *array = [NSMutableArray array];
[dictArr.rac_sequence.signal subscribeNext:^(NSDictionary *dict) {
Flag *flag = [Flag flagWithDict:dict];
[array addObject:flag];
}];
//更高级点的用法
NSArray *flagArr = [[dictArr.rac_sequence map:^id _Nullable(NSDictionary *dict) {
return [Flag flagWithDict:dict];
}] array];
三、开发中常见用法 (转换成信号然后订阅)
1、代替代理:
(1)RACSubject :可以传值
(2)rac_signalForSelector :无法传值
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"控制器知道按钮被点击");
}];
2、代替KVO :
rac_valuesForKeyPath:用于监听某个对象的属性改变。
[[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id x) {
// x:修改的值
NSLog(@"%@",x);
}];
3、监听事件:
rac_signalForControlEvents:用于监听某个事件。
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按钮点击了");
}];
4、代替通知:
rac_addObserverForName:用于监听某个通知。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
5、监听文本框文字改变:
rac_textSignal:只要文本框发出改变就会发出这个信号。
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
6、处理当界面有多次请求时,需要都获取到数据时,才能展示界面
rac_liftSelector:withSignalsFromArray:
Signals:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。
使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
- (void)viewDidLoad {
[super viewDidLoad];
RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//这里进行网络请求
[subscriber sendNext:@"0000000"];
return nil;
}];
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//这里进行网络请求
[subscriber sendNext:@"1111111"];
return nil;
}];
/*
selector方法参数个数必须与信号数组个数一致,表示获得到的数据
rac_liftSelector:必须信号数组中的信号都发送数据才会进入selector方法中
*/
[self rac_liftSelector:@selector(updateUIWithOne:two:) withSignalsFromArray:@[signal0, signal1]];
}
- (void)updateUIWithOne:(NSString *)one two:(NSString *)two{
NSLog(@"one = %@;\ntwo = %@",one,two);
}
四、常见的宏
1、RAC(<#TARGET, ...#>):用于给某个对象的某个属性绑定
// 监听文本框内容
[_textField.rac_textSignal subscribeNext:^(id x) {
_label.text = x;
}];
//使用RAC宏:
// 用来给某个对象的某个属性绑定信号,只要产生信号内容,就会把内容给属性赋值
RAC(_label,text) = _textField.rac_textSignal;
2、RACObserve(self, name):监听某个对象的某个属性,返回的是信号
[RACObserve(self.view, frame) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
3、@weakify(Obj)和@strongify(Obj),一般两个都是配套使用,解决循环引用问题.
//在block外使用@weakify(self),在block內使用@strongify(self),可以防止block内使用self出现循环引用
4、RACTuplePack:把数据包装成RACTuple(元组类)
// 包装元组
RACTuple *tuple = RACTuplePack(@1,@2);
NSLog(@"%@",tuple[0]);
5、RACTupleUnpack:把RACTuple(元组类)解包成对应的数据
NSDictionary *dict = @{@"account":@"aaa",@"name":@"xmg",@"age":@18};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
// RACTupleUnpack:用来解析元组
// 宏里面的参数,传需要解析出来的变量名
// = 右边,放需要解析的元组
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@ %@", key, value);
}];
五、常见操作方法
ReactiveCocoa操作思想
运用的是==Hook(钩子)思想==,Hook是一种用于改变API(应用程序编程接口:方法)执行结果的技术.
Hook用处:截获API调用的技术。
Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出。
RAC开发方式:RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。
列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。
1、核心方法bind
一般不会使用bind方法,因为比较底层
给RAC中的信号进行绑定,只要信号一发送数据,就能监听到,从而把发送数据改成自己想要的数据
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop){
value = [NSString stringWithFormat:@"changed:%@",value];
/*
在这里修改获取到的数据
*/
return [RACReturnSignal return:value];
};
}];
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"数据"];
监听文本框的内容,并绑定
[[self.textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id _Nullable value, BOOL *stop){
value = [NSString stringWithFormat:@"输出:%@",value];
return [RACReturnSignal return:value];
};
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
2、ReactiveCocoa操作方法之映射(flattenMap,Map)
(1)falttenMap
//1、创建信号
RACSubject *subject = [RACSubject subject];
//2、绑定信号
RACSignal *bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
//这里的block只要原信号发送数据就会调用
value = [NSString stringWithFormat:@"lcy:%@",value];
return [RACReturnSignal return:value];
}];
//3、订阅信号
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//4、发送数据
[subject sendNext:@"hello"];
(2)map
RACSubject *subject = [RACSubject subject];
RACSignal *bindSignal = [subject map:^id _Nullable(id _Nullable value) {
//这里返回的值就是需要映射的值
return [NSString stringWithFormat:@"dashabi:%@",value];
}];
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"123123"];
[subject sendNext:@"123123123"];
3、ReactiveCocoa操作方法之组合
(1)concat
按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号。
==注意==:组合中第一个信号一定要调用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送A的数据");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送B的数据");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *concatSignal = [signalA concat:signalB];
[concatSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 16:33:57.588 RAC_learning[3169:192908] 发送A的数据
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello A
2017-07-28 16:33:57.589 RAC_learning[3169:192908] 发送B的数据
2017-07-28 16:33:57.589 RAC_learning[3169:192908] hello B
(2)then
用于连接两个信号,当第一个信号完成,才会连接then返回的信号,then会完全忽略第一个信号的数据
==注意==:组合中第一个信号一定要调用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送A的数据");
[subscriber sendNext:@"hello A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送B的数据");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signal = [signalA then:^RACSignal * _Nonnull{
return signalB;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 16:38:18.436 RAC_learning[3280:196164] 发送A的数据
2017-07-28 16:38:18.440 RAC_learning[3280:196164] 发送B的数据
2017-07-28 16:38:18.440 RAC_learning[3280:196164] hello B
(3)merge
把多个信号合并为一个信号,任何一个信号有新值的时候就会调用
不需要调用sendComplete
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送A的数据");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送B的数据");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
return nil;
}];
RACSignal *signal = [[signalA merge:signalB] merge:signalC];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 16:46:06.471 RAC_learning[3563:202620] 发送A的数据
2017-07-28 16:46:06.471 RAC_learning[3563:202620] hello A
2017-07-28 16:46:06.471 RAC_learning[3563:202620] 发送B的数据
2017-07-28 16:46:06.472 RAC_learning[3563:202620] hello B
(4)zipWith
把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个==元组==(RACTuple),才会触发压缩流的next事件
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送A的数据");
[subscriber sendNext:@"hello A"];
return nil;
}];
RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送B的数据");
[subscriber sendNext:@"hello B"];
return nil;
}];
RACSignal *signal = [signalA zipWith:signalB];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 16:52:44.200 RAC_learning[3630:205690] 发送A的数据
2017-07-28 16:52:44.201 RAC_learning[3630:205690] 发送B的数据
2017-07-28 16:52:44.204 RAC_learning[3630:205690] <RACTwoTuple: 0x6000000173b0> (
"hello A",
"hello B"
)
(5)combineLatest
将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号
(6)reduce
用于信号发出的内容是元组,把信号发出元组的值聚合成一个值
RACSignal *signal = [RACSignal combineLatest:@[self.nameTF.rac_textSignal, self.passwordTF.rac_textSignal] reduce:^id _Nullable(NSString *name, NSString *password){
NSLog(@"%@ ooooo %@",name, password);
return @(name.length && password.length);
}];
// [signal subscribeNext:^(id _Nullable x) {
// NSLog(@"得到的数据:%@",x);
// }];
//使登录按钮在用户名和密码框都有数据的时候才会调用
RAC(self.loginButton, enabled) = signal;
4、ReactiveCocoa操作方法之过滤
(1)filter
过滤信号,使用它可以获取满足条件的信号
RACSignal *signal = [self.nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
//表示当文本框输入的长度超过六位的时候
return value.length > 6;
}];
[signal subscribeNext:^(id _Nullable x) {
//只有满足条件的时候才会进入这个block
NSLog(@"%@",x);
}];
(2)ignore
忽略完某些值的信号.
[[self.nameTF.rac_textSignal ignore:@"000"] subscribeNext:^(NSString * _Nullable x) {
//忽略了字符串是000的值
NSLog(@"%@",x);
}];
(3)distinctUntilChanged
当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉
[[self.nameTF.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
(4)take
从开始一共取N次的信号
[[self.nameTF.rac_textSignal take:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
// 1、创建信号
RACSubject *signal = [RACSubject subject];
// 2、处理信号,订阅信号
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
(5)takeLast
取最后N次的信号
==前提条件==:订阅者必须调用完成,因为只有完成,就知道总共有多少信号
==注意==:一定要调用sendComplete,不然订阅者不知道有多少
RACSubject *subject = [RACSubject subject];
[[subject takeLast:3] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
[subject sendNext:@4];
[subject sendNext:@5];
[subject sendCompleted];
(6)takeUntil
获取信号直到执行完这个信号
RACSubject *subject = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[subject takeUntil:signal] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@1];
[subject sendNext:@2];
/*
sendNext或者sendComplete都可以截止
sendError不可以
*/
[signal sendCompleted];
[subject sendNext:@3];
[subject sendNext:@4];
[subject sendNext:@5];
[subject sendCompleted];
// 监听文本框的改变,直到当前对象被销毁
[_textField.rac_textSignal takeUntil:self.rac_willDeallocSignal];
(7)skip:(NSUInteger)
跳过几个信号,不接受
[[self.nameTF.rac_textSignal skip:3] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
5、ReactiveCocoa操作方法之秩序
doNext: 执行Next之前,会先执行这个Block
doCompleted: 执行sendCompleted之前,会先执行这个Block
[[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"hahaha"];
[subscriber sendCompleted];
return nil;
}] doNext:^(id _Nullable x) {
NSLog(@"doNext");
}] doCompleted:^{
NSLog(@"doComplete");
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
输出:
2017-07-28 18:12:56.704 RAC_learning[5256:261194] doNext
2017-07-28 18:12:56.705 RAC_learning[5256:261194] hahaha
2017-07-28 18:12:56.705 RAC_learning[5256:261194] doComplete
6、ReactiveCocoa操作方法之线程
deliverOn: 内容传递切换到制定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
subscribeOn: 内容传递和副作用都会切换到制定线程中。
7、ReactiveCocoa操作方法之时间
(1)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);
}];
(2)interval
定时,每隔一段时间发出信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"123123123"];
return nil;
}];
[[RACSignal interval:2.0 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",x);
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
(3)delay
延迟发送next
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"123123123"];
return nil;
}] delay:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
8、ReactiveCocoa操作方法之重复
(1)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) {
}];
(2)replay重放
当一个信号被多次订阅,反复播放内容
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//只会进入这个block一次,不会反复进入
[subscriber sendNext:@1];
[subscriber sendNext:@2];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"第一个订阅者%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"第二个订阅者%@",x);
}];
(3)throttle节流
当某个信号发送比较频繁时,可以使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。
R
ACSubject *signal = [RACSubject subject];
_signal = signal;
// 节流,在一定时间(1秒)内,不接收任何信号内容,过了这个时间(1秒)获取最后发送的信号内容发出。
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];