RAC 使用方法总结

RACSignal

/**

*
一.核心:
1.核心:信号类
2.信号类的作用:只要有数据改变就会把数据包装成信号传递出去
3.只要有数据改变就会有信号发出
4.数据发出,并不是信号类发出,信号类不能发送数据
一.使用方法:
1.创建信号
2.订阅信号
二.实现思路:
1.当一个信号被订阅,创建订阅者,并把nextBlock保存到订阅者里面。
2.创建的时候会返回 [RACDynamicSignal createSignal:didSubscribe];
3.调用RACDynamicSignal的didSubscribe
4.发送信号[subscriber sendNext:value];
5.拿到订阅者的nextBlock调用
*/

// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 3.发送信号
[subscriber sendNext:@"ws"];
// 4.取消信号,如果信号想要被取消,就必须返回一个RACDisposable
// 信号什么时候被取消:1.自动取消,当一个信号的订阅者被销毁的时候机会自动取消订阅,2.手动取消,
//block什么时候调用:一旦一个信号被取消订阅就会调用
//block作用:当信号被取消时用于清空一些资源
return [RACDisposable disposableWithBlock:^{
NSLog(@"取消订阅");
}];
}];
// 2. 订阅信号
//subscribeNext
// 把nextBlock保存到订阅者里面
// 只要订阅信号就会返回一个取消订阅信号的类
RACDisposable *disposable = [signal subscribeNext:^(id x) {
// block的调用时刻:只要信号内部发出数据就会调用这个block
NSLog(@"======%@", x);
}];
// 取消订阅
[disposable dispose];

}


RACSignal使用步骤

/**
*1.创建信号
*2.订阅信号(订阅信号后,才会被激活)
*3.发送信号

/RACSignal底层实现
1、创建信号,首先把didSubscribe保存到信号中,还不会触发
2、当信号被订阅,也就是调用signal的subscribrNext:nextBlock, subscribeNext内部会创建订阅者subscriber,并把nextBlock保存到subscriber中,subscribNext内部会调用signal的didSubscribe
3、signal的didsubcribe中调用【subscriber sendNext:@"发送数据"】,sendNext底层其实就是执行subscriber的nextBlock。
*/

 //1.创建信号
RACSignal *mysignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//2.发送信号
[subscriber sendNext:@"发送数据"];

[subscriber sendCompleted];//如果不再发送数据,需要调用完成方法,内部会调用 [self.disposable dispose];

return [RACDisposable disposableWithBlock:^{
NSLog(@"信号被销毁");
}];
}];
//3.订阅信号,才会激活信号
[mysignal subscribeNext:^(id x) {
NSLog(@"接受到数据:%@",x);
}];


RACSubject

/**
*我们完全可以用RACSubject代替代理/通知,确实方便许多
步骤:
// 1.创建信号
RACSubject *subject = [RACSubject subject];

// 2.订阅信号
[subject subscribeNext:^(id x) {
// block:当有数据发出的时候就会调用
// block:处理数据
NSLog(@"%@",x);
}];

// 3.发送信号
[subject sendNext:value];
**注意:~~**
RACSubject和RACReplaySubject的区别
RACSubject必须要先订阅信号之后才能发送信号, 而RACReplaySubject可以先发送信号后订阅.
可按实际情况各取所需。

*/

RACSubject使用步骤

/**
1、创建信号 【RACSubject subject】,跟RACSignal不一样,创建信号时没有block。
2、订阅信号 -(RACDisposable *)subscribeNext:(void(^)(id x)nextBlock)
3、发送信号 sengNext:(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) {
NSLog(@"第二个订阅者:%@",x);
}];

//3、发送信号
[subject sendNext:@1];
[subject sendNext:@2];

可以当通知来使用

也可以当做代理使用(在一个View中定义为属性,外部订阅,内容调用)


RACRepalySubject

//RACRepalySubject使用步骤
/**
1、创建信号 [RACReplaySubject subject] ,跟RACSignal不一样,创建信号时没有block
2、可以先发送信号,再订阅信号,RACSubject不可以!!!
*订阅信号 -(RACDisposable)subscribeNext:(void(^)(id x))nextBlock
*发送信号 sendNext:(id)value

RACReplaySubject:底层实现和RACSubject不一样
1、调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock
2、调用subscribeNext订阅信号,遍历所有保存的值,一个一个调用订阅者的nextBlock

如果想当一个信号被订阅,就重复播放之前所有值,需要先发送信号,再订阅信号
也就是先保存值,再订阅值
*/

//1、创建信号
RACReplaySubject *replaySubject = [RACReplaySubject replaySubjectWithCapacity:3];

//2、发送信号
[replaySubject sendNext:@1];
[replaySubject sendNext:@2];

//3、订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一个订阅者收到的数据%@",x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"第二个订阅者收到的数据%@",x);
}];

两种的输出为:

/**
// 先订阅,后发送信号
2016-08-29 16:18:23.154 RACDemo[5507:185680] 第一个订阅者收到的数据1
2016-08-29 16:18:23.154 RACDemo[5507:185680] 第二个订阅者收到的数据1
2016-08-29 16:18:23.154 RACDemo[5507:185680] 第一个订阅者收到的数据2
2016-08-29 16:18:23.155 RACDemo[5507:185680] 第二个订阅者收到的数据2
*/

/**
// 先发送信号,再订阅
2016-08-29 16:19:43.945 RACDemo[5641:186739] 第一个订阅者收到的数据1
2016-08-29 16:19:43.945 RACDemo[5641:186739] 第一个订阅者收到的数据2
2016-08-29 16:19:43.946 RACDemo[5641:186739] 第二个订阅者收到的数据1
2016-08-29 16:19:43.946 RACDemo[5641:186739] 第二个订阅者收到的数据2
*/

RACSequence

元祖

NSArray

// 遍历数组
NSArray *array = @[@1,@2,@3];

// 1、把数组转换成集合RACSequence,array.rac_seuqence
// 2、把集合RACSequence转换RACSignal信号类,array.rac_sequence.signal
// 3、订阅信号,激活信号,会自动把集合中的所有值,遍历出来
[array.rac_sequence.signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

NSDictionary

 // 遍历字典,遍历出来的键值会包装成RACTuple(元祖对象)
NSDictionary *dic = @{@"name":@"wangtongke",@"age":@18};

[dic.rac_sequence.signal subscribeNext:^(id x) {

// 遍历字典 X为RAC的元祖(RACTuple)
// 解包元祖,会把元祖的值,按顺序给参数里边的变量赋值

RACTupleUnpack(NSString *key,NSString *value) = x;

// 以上 相当于一下写法
// NSString *key1 = x[0];
// NSString *value1 = x[1];

NSLog(@"%@ %@\n",key,value);

}];

RACComand

    /**
1、创建命令 initWithSignalblock:(RACSignal * (^)(id input))signalBlock
2、在signalBlock中,创建RACSignal,并且作为signalBlock的返回值
3、执行命令 -(RACSignal *)execute:(id)input

// 注意事项
1、signalBlock必须要返回一个signal,不能返回nil,
2、如果不想要传递信号,直接创建空的信号返回[RACSignal empty];
3、RACCommand,如果数据传递完毕,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中.
4、RACComand需要被强引用,否则接手不到RACCommand中的信号,因此,RACCommand中的信号是延迟发送的。

// 设计思想 : 内部signalBlock为什么要返回一直信号,这个信号有什么用
1、在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。
2、当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了

// 如何拿到RACCommand中返回信号发出的数据
1、RACCommand有个执行信号源executionSignal,这个signal of signal(信号的信号),意思是发出的数据是信号,不是普通的类型
2、订阅executionSignal就能拿到RACCommand中返回的信号,然后订阅signalblock返回的信号。

// 监听当前命令是否正在执行executing
// 使用场景 按钮点击,网络请求
*/

// ******* 1、创建命令
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"执行命令");
NSLog(@"input---%@",input);
//必须返回信号 不能返回nil 创建空信号,
//return [RACSignal empty];

// ******* 2、创建信号,用来传递数据

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

[subscriber sendNext:@"请求数据"];
[subscriber sendNext:@"请求数据1"];
//注意:数据传递完,必须调用sendCompleted,这时命令才执行完毕
[subscriber sendCompleted];

return [RACDisposable disposableWithBlock:^{

}];
}];
}];

//强引用命令,不然会自动销毁,接受不到数据
_command = command;

// ******* 3、订阅RACCommand中的信号
[command.executionSignals subscribeNext:^(id x) {
[x subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
}];

//高级用法
//switchToLatest:用于signal of signals,获取signal of signals 发出的最新的信号,也就是可以直接拿到RACCommand中的信号
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"高级--%@",x);
}];

// ******** 4、监听命令是否执行完毕,默认会来一次,可以直接跳过,skip表示跳过第一次信号
[[command.executing skip:0] subscribeNext:^(id x) {
if ([x boolValue] == YES)
{
//正在执行
NSLog(@"正在执行");
}
else
{
//执行完成
NSLog(@"执行完成");
}
}];

// ******** 5、执行命令
[self.command execute:@1];


RACMulticastConnection

解决多次订阅多次请求的问题,只有连接之后才调用所有订阅者的subscribeNext

/**
RACMulticastConnection使用步骤

**** 1、创建信号 +(RACSignal)createSignal
**** 2、创建连接 RACMulticastConnection *connect = [signal publish];
**** 3、订阅信号,注意:订阅的不再是之前的信号,而是连接的信号[connect.signal subscribeNext];
**** 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(@"发送请求111111");
[subscriber sendNext:@1];
return nil;
}];

// ********** 2、订阅信号
[signal subscribeNext:^(id x) {
NSLog(@"接受数据11111--%@",x);
}];
// 订阅两次信号
[signal subscribeNext:^(id x) {
NSLog(@"接受数据11111---%@",x);
}];

//会执行两次发送请求。也就是每订阅一次 就会发送一次请求

//RACMulicastConnection解决重复请求问题
// ********** 1、创建信号

RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

NSLog(@"发送请求2");
[subscriber sendNext:@1];

return nil;
}];
// ********** 2、 创建连接
RACMulticastConnection *connect = [signal2 publish];

// ********** 3、订阅信号
// 注意:订阅信号也不能激活信号,只是保存订阅者到数据,必须通过连接,当调用连接,就会一次清调用所有订阅者的sendNext;
[connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者一信号");
}];

[connect.signal subscribeNext:^(id x) {
NSLog(@"订阅者二信号");
}];

// ********** 4、连接
[connect connect];


bind

/**

假设想监听文本框的内容,并且在每次输出结果的时候,都在文本框的内容拼接一段文字“输出:”
*/

// bind(绑定)的使用思想和Hook的一样---> 都是拦截API从而可以对数据进行操作,,而影响返回数据。
// 发送信号的时候会来到30行的block。在这个block里我们可以对数据进行一些操作,那么35行打印的value和订阅绑定信号后的value就会变了。变成什么样随你喜欢喽。


// ******************方式1、 在返回结果后拼接
// [_textField.rac_textSignal subscribeNext:^(id x) {
// NSLog(@"输出:%@",x);
// }];

// ******************方式2、在返回结果前拼接,使用RAC中的bind方法做处理
/**
bind方法参数:需要传入一个返回值是RACSignalBindBlock的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、描述
*/
[[_textField.rac_textSignal bind:^RACStreamBindBlock{

return ^RACStream *(id value,BOOL *stop){
return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]];
};
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];


// 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.绑定信号
RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{
// block调用时刻:只要绑定信号订阅就会调用。不做什么事情,
return ^RACSignal *(id value, BOOL *stop){
// 一般在这个block中做事 ,发数据的时候会来到这个block。
// 只要源信号(subject)发送数据,就会调用block
// block作用:处理源信号内容
// value:源信号发送的内容,
value = @3; // 如果在这里把value的值改了,那么订阅绑定信号的值即44行的x就变了
NSLog(@"接受到源信号的内容:%@", value);
//返回信号,不能为nil,如果非要返回空---则empty或 alloc init。
return [RACReturnSignal return:value]; // 把返回的值包装成信号
};
}];

// 3.订阅绑定信号
[bindSignal subscribeNext:^(id x) {

NSLog(@"接收到绑定信号处理完的信号:%@", x);
}];
// 4.发送信号
[subject sendNext:@"123"];

RACMethod


// ********************** 1、代替代理 **************************

/**
需求: 自定义redView,监听redView中按钮点击
之前都是需要通过代理监听,给红色view添加一个代理属性,点击按钮的时候,通知代理做事情
rac_signalForSelector:把调用某个对象的方法的信息转换成信号,只要调用这个方法,就会发送信号
这里表示只要redView调用btnClick,就会发出信号,只需要订阅就可以了

*/
WTKView *view = [[WTKView alloc]initWithFrame:CGRectMake(0, 200, 375, 200)];
[self.view addSubview:view];

[[view rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"点击红色按钮---%@",x);
//怎么传值????
}];

// ********************** 2、KVO **************************
[[view rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
view.center = CGPointMake(100, 100);



// ********************** 3、监听事件 **************************
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.backgroundColor = [UIColor purpleColor];
btn.frame = CGRectMake(300, 300, 200, 30);
[btn setTitle:@"RAC" forState:UIControlStateNormal];
[self.view addSubview:btn];

[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"按钮被点击了");
}];


// ********************** 4、代替通知 **************************
// 把监听到的通知,转换成信号
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"键盘弹出");
}];


// ********************** 5、监听文本框文字改变 **************************

[self.textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"文字改变了---%@",x);
}];


// ********************** 6、处理多个请求,都返回结果的时候,统一做处理 **************************

RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

[subscriber sendNext:@"发送请求1"];


return [RACDisposable disposableWithBlock:^{

}];
}];
RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {


dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"发送请求2"];
});

return [RACDisposable disposableWithBlock:^{

}];
}];

// 使用注意:几个信号,参数一的方法就必须有几个参数,每个参数对应信号发出的数据
[self rac_liftSelector:@selector(wtkUpdateWithDic1:withDic2:) withSignalsFromArray:@[request1,request2]];


skip

// 跳跃 : 如下,skip传入2 跳过前面两个值
//应用场景: 在实际开发中比如 后台返回的数据前面几个没用,我们想跳跃过去,便可以用skip
- (void)skip {
RACSubject *subject = [RACSubject subject];
[[subject skip:2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
}


distinctUntilChanged

//应用场景:-- 如果当前的值跟上一次的值一样,就不会被订阅到
- (void)distinctUntilChanged {
RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@2]; // 不会被订阅
}

take

// 应用场景:可以屏蔽一些值,去前面几个值---这里take为2 则只拿到前两个值
- (void)take {
RACSubject *subject = [RACSubject subject];
[[subject take:2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
}

takeLast

//应用场景:和take的用法一样,不过他取的是最后的几个值,如下,则取的是最后两个值
//注意点:takeLast 一定要调用sendCompleted,告诉他发送完成了,这样才能取到最后的几个值
- (void)takeLast {
RACSubject *subject = [RACSubject subject];
[[subject takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号
[subject sendNext:@1];
[subject sendNext:@2];
[subject sendNext:@3];
[subject sendCompleted];
}

takeUntil

//应用场景:---给takeUntil传的是哪个信号,那么当这个信号发送信号或sendCompleted,就不能再接受源信号的内容了。
- (void)takeUntil {
RACSubject *subject = [RACSubject subject];
RACSubject *subject2 = [RACSubject subject];
[[subject takeUntil:subject2] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号
[subject sendNext:@1];
[subject sendNext:@2];
[subject2 sendNext:@3]; // 1
// [subject2 sendCompleted]; // 或2
[subject sendNext:@4];
}

ignore

//应用场景: 忽略掉一些值
- (void)ignore {
//ignore:忽略一些值
//ignoreValues:表示忽略所有的值
// 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.忽略一些值
RACSignal *ignoreSignal = [subject ignore:@2]; // ignoreValues:表示忽略所有的值
// 3.订阅信号
[ignoreSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 4.发送数据
[subject sendNext:@2];

}

fliter

// 一般和文本框一起用,添加过滤条件
- (void)fliter {
// 只有当文本框的内容长度大于5,才获取文本框里的内容
[[self.textField.rac_textSignal filter:^BOOL(id value) {
// value 源信号的内容
return [value length] > 5;
// 返回值 就是过滤条件。只有满足这个条件才能获取到内容
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
}

map

- (void)map {
// 创建信号
RACSubject *subject = [RACSubject subject];
// 绑定信号
RACSignal *bindSignal = [subject map:^id(id value) {

// 返回的类型就是你需要映射的值
return [NSString stringWithFormat:@"ws:%@", value]; //这里将源信号发送的“123” 前面拼接了ws:
}];
// 订阅绑定信号
[bindSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号
[subject sendNext:@"123"];

}

flattenMap

应用场景: 主要用于信号中的信号

- (void)flattenMap {
// 创建信号
RACSubject *subject = [RACSubject subject];
// 绑定信号
RACSignal *bindSignal = [subject flattenMap:^RACStream *(id value) {
// block:只要源信号发送内容就会调用
// value: 就是源信号发送的内容
// 返回信号用来包装成修改内容的值
return [RACReturnSignal return:value];

}];

// flattenMap中返回的是什么信号,订阅的就是什么信号(那么,x的值等于value的值,如果我们操纵value的值那么x也会随之而变)
// 订阅信号
[bindSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送数据
[subject sendNext:@"123"];
}

- (void)flattenMap2 {

// 创建信号
RACSubject *signalofSignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];

// 订阅信号
//方式1
// [signalofSignals subscribeNext:^(id x) {
//
// [x subscribeNext:^(id x) {
// NSLog(@"%@", x);
// }];
// }];
// 方式2
// [signalofSignals.switchToLatest ];
// 方式3
// RACSignal *bignSignal = [signalofSignals flattenMap:^RACStream *(id value) {
//
// //value:就是源信号发送内容
// return value;
// }];
// [bignSignal subscribeNext:^(id x) {
// NSLog(@"%@", x);
// }];
// 方式4--------也是开发中常用的
[[signalofSignals flattenMap:^RACStream *(id value) {
return value;
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];

// 发送信号
[signalofSignals sendNext:signal];
[signal sendNext:@"123"];
}

RAC常见宏

    // RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定。
RAC(self.label,text) = _textField.rac_textSignal;

// RACObserve(self, name):监听某个对象的某个属性,返回的是信号

[RACObserve(self.label, text) subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

// @weakify(Obj)和@strongify(Obj),一般两个都是配套使用,在主头文件(ReactiveCocoa.h)中并没有导入,需要自己手动导入,RACEXTScope.h才可以使用。但是每次导入都非常麻烦,只需要在主头文件自己导入就好了。
// 最新版库名 已换成 EXTScope
// 两个配套使用,先weak再strong
@weakify(self);
// @strongify(self);
[RACObserve(self, label.text) subscribeNext:^(id x) {
@strongify(self);
}];


// RACTuplePack:把数据包装成RACTuple(元组类)
// 把参数中的数据包装成元祖
RACTuple *tuple = RACTuplePack(@10,@20);


// RACTupleUnpack:把RACTuple(元组类)解包成对应的数据。
// 把参数再用的数据包装成元祖

组合

combineLatest

//使用场景: 把多个信号聚合成你想要的信号,使用场景----:比如-当多个输入框都有值的时候按钮才可点击。
// 思路--- 就是把输入框输入值的信号都聚合成按钮是否能点击的信号。
- (void)combineLatest {

RACSignal *combinSignal = [RACSignal combineLatest:@[self.accountField.rac_textSignal, self.pwdField.rac_textSignal] reduce:^id(NSString *account, NSString *pwd){ //reduce里的参数一定要和combineLatest数组里的一一对应。
// block: 只要源信号发送内容,就会调用,组合成一个新值。
NSLog(@"%@ %@", account, pwd);
return @(account.length && pwd.length);
}];

// // 订阅信号
// [combinSignal subscribeNext:^(id x) {
// self.loginBtn.enabled = [x boolValue];
// }]; // ----这样写有些麻烦,可以直接用RAC宏
RAC(self.loginBtn, enabled) = combinSignal;
}

zipWith

//使用场景:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元祖,才会触发压缩流的next事件。

- (void)zipWith {
// 创建信号A
RACSubject *signalA = [RACSubject subject];
// 创建信号B
RACSubject *signalB = [RACSubject subject];
// 压缩成一个信号
// **-zipWith-**: 当一个界面多个请求的时候,要等所有请求完成才更新UI
// 等所有信号都发送内容的时候才会调用
RACSignal *zipSignal = [signalA zipWith:signalB];
[zipSignal subscribeNext:^(id x) {
NSLog(@"%@", x); //所有的值都被包装成了元组
}];

// 发送信号 交互顺序,元组内元素的顺序不会变,跟发送的顺序无关,而是跟压缩的顺序有关[signalA zipWith:signalB]---先是A后是B
[signalA sendNext:@1];
[signalB sendNext:@2];

}

merge

// 任何一个信号请求完成都会被订阅到
//使用场景:多个信号合并成一个信号,任何一个信号有新值就会调用
- (void)merge {
// 创建信号A
RACSubject *signalA = [RACSubject subject];
// 创建信号B
RACSubject *signalB = [RACSubject subject];
//组合信号
RACSignal *mergeSignal = [signalA merge:signalB];
// 订阅信号
[mergeSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
// 发送信号---交换位置则数据结果顺序也会交换
[signalB sendNext:@"下部分"];
[signalA sendNext:@"上部分"];
}

then

//使用场景:有两部分数据:想让上部分先进行网络请求但是过滤掉数据,然后进行下部分的,拿到下部分数据
- (void)then {
// 创建信号A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求
NSLog(@"----发送上部分请求---afn");

[subscriber sendNext:@"上部分数据"];
[subscriber sendCompleted]; // 必须要调用sendCompleted方法!
return nil;
}];

// 创建信号B,
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求
NSLog(@"--发送下部分请求--afn");
[subscriber sendNext:@"下部分数据"];
return nil;
}];
// 创建组合信号
// then;忽略掉第一个信号的所有值
RACSignal *thenSignal = [signalA then:^RACSignal *{
// 返回的信号就是要组合的信号
return signalsB;
}];

// 订阅信号
[thenSignal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];

}

concat

//使用场景:有两部分数据:想让上部分先执行,完了之后再让下部分执行(都可获取值)
- (void)concat {
// 组合

// 创建信号A
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求
// NSLog(@"----发送上部分请求---afn");

[subscriber sendNext:@"上部分数据"];
[subscriber sendCompleted]; // 必须要调用sendCompleted方法!
return nil;
}];

// 创建信号B,
RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求
// NSLog(@"--发送下部分请求--afn");
[subscriber sendNext:@"下部分数据"];
return nil;
}];


// concat:按顺序去链接
//**-注意-**:concat,第一个信号必须要调用sendCompleted
// 创建组合信号
RACSignal *concatSignal = [signalA concat:signalsB];
// 订阅组合信号
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

}

网路请求应用场景

 RACCommand *reuqesCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {

RACSignal *requestSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"test"] = @"";

// 发送请求
[[AFHTTPRequestOperationManager manager] GET:@"https://api.douban.com/v2/book/search" parameters:parameters success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(@"%@",responseObject);

// 请求成功调用
// 把数据用信号传递出去
[subscriber sendNext:responseObject];

[subscriber sendCompleted];


} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
// 请求失败调用

}];

return nil;
}];

// 在返回数据信号时,把数据中的字典映射成模型信号,传递出去
return [requestSignal map:^id(NSDictionary *value) {
NSMutableArray *dictArr = value[@"Persions"];

// 字典转模型,遍历字典中的所有元素,全部映射成模型,并且生成数组
NSArray *modelArr = [[dictArr.rac_sequence map:^id(id value) {

return [Persion bookWithDict:value];
}] array];

return modelArr;
}];

}];


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值