ReactiveCocoa基础
ReactiveCocoa使用详解
ReactiveCocoa 博客
ReactiveCocoa基础
1.信号类RACsignal
//1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
NSLog(@"信号被订阅了");
//3.发送数据
[subscriber sendNext:@"1"];
return [RACDisposable disposableWithBlock:^{
//subscriber订阅者释放就会来这里
//只要取消订阅就会来这
//清空一些资源
WJLog(@"信号被取消订阅了");
}];
}];
//2.订阅信号
RACDisposable *disposable = [signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//4.取消订阅。
[disposable dispose];
2.信号类RACSubject
//RACSubject 可以替代代理。
//1.创建信号
RACSubject *subject = [RACSubject subject];
//2.订阅信号
[subject subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
//保存订阅者
//3.发送信号
[subject sendNext:@"1"];
//底层实现:遍历所有的订阅者,调用nextBlock。
//执行流程
//RACSubject被订阅,仅仅是保存订阅者
//RACSubject发送数据,遍历所有的订阅者,调用他们的nextBlock
3.信号类RACReplaySubject
//1.创建信号。
RACReplaySubject *subject = [RACReplaySubject subject];
//3.发送信号。
[subject sendNext:@"1"];
//2.订阅信号。
[subject subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
//遍历所有的值,拿到当前的订阅者去发送数据。
//RACReplaySubject发送数据:
//1.保存值
//2.遍历所有的订阅者,发送数据。
//RACReplaySubject可以先发送信号,再订阅信号。
//RACReplaySubject *subject = [RACReplaySubject replaySubjectWithCapacity:10];//设置缓冲区个数。
4.集合类RACSequence和RACTuple
//1.数组遍历
NSArray *numbers = @[@(1),@(2),@(3),@(4)];
//这里其实是三步:
//第一步:把数组转换成集合RACSequence numbers.rac_sequence
//第二步:把集合RACSequence转换RACSignal信号类,numbers.rac_sequence.signal
//第三步:订阅信号,激活信号,会自动把集合中的所有值,遍历出来。
[numbers.rac_sequence.signal subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
//2.遍历字典,遍历出来的键值对会包装成RACTuple(元组对象)
NSDictionary *dict = @{@"name":@"xhg",@"age":@(18)};
[dict.rac_sequence.signal subscribeNext:^(id x) {
//解包元组,会把元组的值,按顺序给参数里面的变量赋值。
RACTupleUnpack(NSString *key,NSString *value) = x;
//相当于下面的写法。
//NSString *key = x[0];
//NSString *value = x[1];
}];
//3.高级用法
//会把集合中的所有元素映射成一个新的对象(字典转模型)
NSArray *flagArray = [[numbers.rac_sequence map:^id(NSDictionary *value) {
//value:集合中的元素。
return [Flag flagWithDict:value];
}] array];
5.连接类RACMulticastConnection
//不管订阅多少次信号,就会请求一次
//RACMulticastConnection:必须要有信号
//1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
WJLog(@"发送热门模块的请求");
//发送信号
[subscriber sendNext:@"1"];
return nil;
}];
//2.把信号转换成连接类
RACMulticastConnection *connection = [signal publish];
//3.订阅连接类的信号
[connection.signal subscribeNext:^(id x) {
WJLog(@"订阅者一%@",x);
}];
[connection.signal subscribeNext:^(id x) {
WJLog(@"订阅者二%@",x);
}];
//4.连接 (必须先订阅后连接)
[connection connect];
//不执行的block
[connection.signal subscribeNext:^(id x) {
WJLog(@"订阅者三%@",x);
}];
//高级用法
RACMulticastConnection *connect2 = [signal multicast:[RACReplaySubject subject]];
//连接(可以先连接后订阅)
[connect2 connect];
[connect2.signal subscribeNext:^(id x) {
WJLog(@"订阅者四%@",x);
}];
ReactiveCocoa宏
1.@weakify与@strongify
//监听文本框内容
@weakify(self);
[self.textField.rac_textSignal subscribeNext:^(id x) {
@strongify(self);
self.label.text = x;
}];
2.RAC(<#TARGET, ...#>)
//用来给某个对象的某个属性绑定信号,只要产生信号内容,就会把内容给属性赋值。
RAC(self.label,text) = self.textField.rac_textSignal;
3.RACObserve(<#TARGET, ...#>)
//2.RACObserve宏
//只要这个对象的属性一改变就会产生信号
[RACObserve(self.view, frame) subscribeNext:^(id x) {
}];
ReactiveCocoa进阶
1.代替代理
//1.代替代理 1.RACSubject 2.rac_signalForSelector
//只要传值就必须使用RACSubject
[[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
WJLog(@"btn 被点击了");
}];
2.代替KVO
//2.代替KVO
[[_redView rac_valuesAndChangesForKeyPath:@"frame" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld |NSKeyValueObservingOptionInitial observer:nil] subscribeNext:^(id x) {
}];
//需要导入#import "NSObject+RACKVOWrapper.h"
[_redView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
}];
//使用RACObserve(<#TARGET#>, <#KEYPATH#>)
[RACObserve(_redView, frame) subscribeNext:^(id _Nullable x) {
}];
3.代替通知
//3.代替通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(id x) {
}];
4.监听文本框
//4.监听文本框
[textField.rac_textSignal subscribeNext:^(id x) {
}];
5.命令RACCommand
//RACCommand:处理事件
//RACCommand:不能返回一个空的信号
//当前命令内部发送数据完成,一定要主动发送完成。
//1.创建命令
_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
//input:执行命令传入的参数
//Block调用:执行命令的时候就会调用。
WJLog(@"%@",input);
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
//发送数据。
[subscriber sendNext:@"发送执行数据"];
//发送完成。
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
WJLog(@"释放");
}];
}];
}];
//如何拿到执行命令中产生的数据
//订阅命令内部的信号。
//1.方式一:直接订阅执行命令返回信号。
//2.执行命令
RACSignal *signal = [_command execute:@1];
[signal subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
//2.方式二:订阅信号
//注意:必须要在执行命令前订阅。
//executionSignals:信号源,信号中信号,signalOfSignals:信号:发送数据就是信号。
[_command.executionSignals subscribeNext:^(RACSignal *x) {
[x subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
}];
//监听事件有没有完成(BOOL)
[_command.executing subscribeNext:^(id x) {
if ([x boolValue] == YES) {
NSLog(@"当前正在执行");
}else{
NSLog(@"执行完成/没有执行");
//确保_command强引用,提前释放将不再执行这一步。
}
}];
//方式二:简化用法
//switchToLatest获取最新发送的信号,只能用于信号中信号。(信号中的信号)
//switchToLatest:获取信号中的信号发送的最新信号。
[_command.executionSignals.switchToLatest subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
[_command execute:@"开始执行"];
ReactiveCocoa高级
1.映射map:(常用)
//创建信号
RACSubject *subject = [RACSubject subject];
//绑定信号
RACSignal *signal = [subject map:^id(id value) {
//返回的类型,就是你需要映射的值
return [NSString stringWithFormat:@"xmg:%@",value];
}];
//订阅绑定信号
[signal subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
[subject sendNext:@"1"];
2.映射信号flattenMap:(转换成新的信号)
//创建信号
RACSubject *subject = [RACSubject subject];
//绑定信号
RACSignal *bindSignal = [subject flattenMap:^id(id value) {
//Block调用:只要源信号发送内容就会调用
//value:就是源信号发送的内容
value = [NSString stringWithFormat:@"xmg:%@",value];
//返回的信号,就是要包装的值。
return [RACReturnSignal return:value];
}];
//flattenMap中返回的是什么信号,订阅的就是什么信号。
//订阅信号
[bindSignal subscribeNext:^(id x) {
WJLog(@"%@",x);
}];
//发送数据
[subject sendNext:@"123"];
3.绑定信号bind:(底层核心,一般不用)
//1.创建信号
RACSubject *subject = [RACSubject subject];
//2.绑定信号
RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{
return ^RACSignal *(id value, BOOL *stop){
//Block调用:只要源信号发送数据,就会调用Block
//Block作用:处理源信号内容
//value:源信号发送的内容
WJLog(@"接收到源信号的内容%@",value);
value = [NSString stringWithFormat:@"xmg:%@",value];
//返回信号,不能传nil,返回空信号
//return [RACSignal empty];
return [RACReturnSignal return:value];
};
}];
//3.订阅绑定信号
[bindSignal subscribeNext:^(id x) {
WJLog(@"接收到绑定信号处理完的信号%@",x);
}];
//4.发送数据
[subject sendNext:@"123"];