学习准备
其实很早之前了解RAC并有意学习,只是没有时间写下来,对于一个开发者RAC确实妙不可言,但是也不要盲目的使用,毕竟学习成本较高,不是很熟练的同学实际运用上可能开发效率反而下降.我使用的是ReactiveCocoa2.5版本,准备开始学习!!
写了3个label用来输出:
self.lbl_1 = [UILabel new];
self.lbl_1.backgroundColor = [UIColor grayColor];
self.lbl_2 = [UILabel new];
self.lbl_2.backgroundColor = [UIColor grayColor];
self.lbl_3 = [UILabel new];
self.lbl_3.backgroundColor = [UIColor grayColor];
然后直接进入第一部分的学习:RACSignal
创建RACSignal
在RAC中有很多种信号,首先是创建这些信号:
1.创建单元信号
- (void)unitSignal{
self.title = @"单元信号";
//发送某个值,通过next可以订阅到
RACSignal *signal1 = [RACSignal return:@"123"];
//发送某个错误,通过error可以订阅到
RACSignal *signal2 = [RACSignal error:[NSError errorWithDomain:@"com.xxx" code:123 userInfo:@{@"error":@"错误123"}]];
//发送某个空信号,发送即完成,可以通过订阅完成信号订阅到
RACSignal *signal3 = [RACSignal empty];
//订阅不到该信号
RACSignal *signal4 = [RACSignal never];
[signal1 subscribeNext:^(id x) {
self.lbl_1.text = x;
}];
[signal2 subscribeError:^(NSError *error) {
self.lbl_2.text = error.description;
}];
[signal3 subscribeCompleted:^{
self.lbl_3.text = @"空信号";
}];
[signal4 subscribeNext:^(id x) {
self.lbl_1.text = @"321";
}];//订阅不到
}
2.创建一般的信号及其实质
- (void)CommonlyCreate{
self.title = @"常用信号创建方法";
//最常用的方式
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
//这个信号里面有一个Next事件和一个Complete事件
[subscriber sendNext:@"新的信号1"];//新的信号
[subscriber sendCompleted];//信号抵达,取消订阅
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁资源");
}];
}];
//订阅新的信号1
[signal1 subscribeNext:^(id x) {
self.lbl_1.text = x;
}];
[signal1 subscribeCompleted:^{
self.lbl_2.text = @"信号抵达,取消订阅";
}];
[signal1 subscribeError:^(NSError *error) {
self.lbl_3.text = error.description;
}];//没有发送错误信号
}
创建信号实质上是其实保存一个block,订阅者也copy了一份block,"send"则是执行这个block,但是sendNext不会先取消订阅,而后两者则会先取消订阅再执行block.
3.UI信号,最常用的是rac_signalForSelector:和rac_textSignal,当然还有很多,可以查看rac的那些分类
- (void)signalToUIView{
self.title = @"UI信号";
//大多数我们和UI交互的事件都可以创建相对应的信号
RACSignal *s1 = [self.tf_1 rac_textSignal];
RACSignal *s2 = [self.view rac_signalForSelector:@selector(setBackgroundColor:)];
RACSignal *s3 = [self.tf_2 rac_signalForSelector:@selector(setTag:)];
[s1 subscribeNext:^(id x) {
NSLog(@"%@",x);
self.lbl_1.text = x;
}];
[s2 subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[s3 subscribeNext:^(id x) {
NSLog(@"%@",x);
self.lbl_2.text = [NSString stringWithFormat:@"tag=%@",x];
}];
//发送信号
self.view.backgroundColor = [UIColor greenColor];
self.tf_2.tag = 1;
}
4.代理方法信号,可以替代无返回值的代理
- (void)RACDelegate
{
RACSignal *proSignal = [self rac_signalForSelector:@selector(textFieldShouldBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)];
[proSignal subscribeNext:^(id x) {
_lbl_1.text = @"开始输入了!";
}];
}
5.KVO信号
RACSignal *kvoSignal = RACObserve(self, property1);
6.通知信号
RACSignal * notificationSignal =[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"haha" object:nil];
7.时间信号
延迟时间信号
[[RACScheduler mainThreadScheduler]afterDelay:1 schedule:^{
NSLog(@"1秒后执行");
}];
定时信号
//每隔1秒执行一次,这里要加takeUntil条件限制一下否则当控制器pop后依旧会执行
RACSignal *timeSignal = [[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] takeUntil:self.rac_willDeallocSignal ] subscribeNext:^(id x) {
NSLog(@"每1秒执行一次");
}
订阅RACSignal
上面我为了显示信号已经写了最常用的订阅方法
RACSignal *signal1 = [_tf_1 rac_textSignal];
RACDisposable *disposeable = [signal1 subscribeNext:^(id x) {
//...
}];
[disposeable dispose];
其实还有宏订阅
//单向订阅
RACSignal *signal1 = [_tf_1 rac_textSignal];
RAC(self.lbl_1,text) = signal1;
self.lbl_1.text = @"112";
甚至双向订阅
//双向订阅(不会实时传递,冷信号??)
RACChannelTo(self.lbl_1,text) = RACChannelTo(self.tf_1,text);
self.lbl_1.text = @"112";
RACSignal的骚操作
1.按钮点击事件(rac_signalForControlEvents)
@weakify(self);
[[self.btn_1 rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(id x) {
@strongify(self);
[self test];
}];
2.组合信号(combineLatest)
直接组合,信号结果按顺序订阅
//信号组合,注意把id改为RACTuple
[[RACSignal combineLatest:@[self.tf_1.rac_textSignal,self.tf_2.rac_textSignal]]subscribeNext:^(RACTuple* x) {
self.lbl_1.text = x.first;
self.lbl_2.text = x.second;
}];
带reduce,可以对接收的参数进行操作
// 带reduce,可以对接收的参数进行操作后返回,想返回什么就返回什么,后面订阅时类型要一定对应一致
[[RACSignal combineLatest:@[self.tf_1.rac_textSignal,self.tf_2.rac_textSignal] reduce:^id(NSString *txt1,NSString *txt2){
return @[[NSString stringWithFormat:@"%@+%@",txt1,txt2],[NSString stringWithFormat:@"%@+%@",txt2,txt1]];//返回数组
}]subscribeNext:^(NSArray* x) {//也是数组
self.lbl_1.text = x.firstObject;
self.lbl_2.text = x.lastObject;
}];
3.信号改进(map)
拦截你的信号,改变成你想要的返还,比如我们下载图片的时候,接口返回的是NSData流,我们可以通过这个方法转为UIImage返回(不是代码内容)
RACSignal *signalA = [_tf_1 rac_textSignal];
//对信号进行改进,当信号里面是”123”,就改成”数字”返还
RAC(self.lbl_1,text) = [signalA map:^id(NSString* value) {
if ([value isEqualToString:@"123"]) {
return @"数字";
}
return value;
}];
4.合并信号(merge)
注意与上面组合信号combineLatest的区别
- (void)mergeSignal{
RACSignal *signalA = [_tf_1 rac_textSignal];
RACSignal *signalB = [_tf_2 rac_textSignal];
RACSignal *signalC = [_tf_3 rac_textSignal];
//合并信号
RACSignal *merge = [RACSignal merge:@[signalA,signalB,signalC]];
[merge subscribeNext:^(id x) {
self.lbl_1.text = x;
}];
}
5.开关信号(filter)
RACSignal *signalA = [_tf_1 rac_textSignal];
RACSignal *signalB = [_tf_2 rac_textSignal];
RACSignal *signalC = [_tf_3 rac_textSignal];
//合并信号
RACSignal *merge = [[RACSignal merge:@[signalA,signalB,signalC]]filter:^BOOL(id value) {
//开关,注意只能有一个return
return [value isEqualToString:@"1"];
}];
[merge subscribeNext:^(id x) {
self.lbl_1.text = x;
}];
6.忽略信号(ignore)
- (void)ignore{
//当信号传输的数据时ignore后的参数时,订阅者就会忽略这个信号,一般用来判断非空
RACSignal *signalA = [_tf_1 rac_textSignal];
[[[signalA ignore:@"1"] ignore:@"2"] subscribeNext:^(id x) {
NSLog(@"%@",x);
self.lbl_1.text = x;
}];
}
结尾
以上列举了一些RACSignal的常见用法,然后还有take/skip bind等等,但今天就先到这里了,有补充的评论我吧!