在这里衷心感谢RAC框架作者mdiep大神,cocoachina论坛的Noah前辈和github的雷纯锋前辈对几个问题的指导
RAC的使用技巧
代替代理
-
使用RAC代替代理时,rac_signalForSelector: fromProtocol:这个代替代理的方法使用时,切记要将self设为代理这句话放在订阅代理信号的后面写,否则会无法执行
//这里订阅收到的是一个x,当一个页面存在多个tableview时,我们可以对x进行判断看是哪个tableview [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:) fromProtocol:@protocol(UITableViewDelegate) ] subscribeNext:^(RACTuple * x) { NSLog(@"点击了"); NSLog(@"%@,%@",x.first,x.second); }]; //这样子不带协议是无法代替代理的,虽然能达到效果,这个方法表示某个selector被调用时执行一段代码.带有协议参数的表示该selector实现了某个协议,所以可以用它来实现Delegate。 // [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:)] subscribeNext:^(RACTuple* x) { // NSLog(@"%@",[x class]); // NSLog(@"%@",x); // }]; //这里是个坑,必须将代理最后设置,否则信号是无法订阅到的 //雷纯峰大大是这样子解释的:在设置代理的时候,系统会缓存这个代理对象实现了哪些代码方法 //如果将代理放在订阅信号前设置,那么当控制器成为代理时是无法缓存这个代理对象实现了哪些代码方法的 tableview.delegate = self;
代替KVO
-
使用RAC代替KVO很简单,一句话就可以搞定,而且相比传统的KVO,不仅代码不用放在一起写美观了很多,同时还能达到高聚合低耦合的目标
//代替KVO [RACObserve(scrollView, contentOffset) subscribeNext:^(id x) { NSLog(@"%@",x); }];
监听事件
-
同样简单,一句话搞定
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@"点击了按钮"); }];
代替通知
- 这里是有个坑的,单纯的写完订阅通知的信号会发现每次都会执行,而且叠加次数会增加,效果如图所示,所以我们要想办法把通知订阅的信号给释放掉,所以用到了takeUntil这个方法,后面我会把它和别的方法放在一起详细讲的
图片若无法看到请点击这里
-
以textfiled成为第一响应者接收键盘弹出的通知为例,我们可以这么写通知
//代替通知 //takeUntil会接收一个signal,当signal触发后会把之前的信号释放掉 [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) { NSLog(@"键盘弹出"); }];
-
这个方法虽然能得到相同的效果,但并不能代替通知
//这个写法有个问题,这样子写信号不会被释放,当你再次收到键盘弹出的通知时他会叠加上次的信号进行执行,并一直叠加下去,所以我们在用上面的写法 // [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(id x) { // NSLog(@"键盘弹出"); // }];
-
这里再给大家举例一个写法思路,可以自己创建一个信号,当这个信号执行时通知会被释放
//这里这样写只是为了给大家开拓一种思路,selector的方法可以应需求更改,即当这个方法执行后,产生一个信号告知控制器释放掉这个订阅的信号 RACSignal * deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)]; [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"haha" object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) { NSLog(@"haha"); }];
定时器
-
延时执行
//五秒后执行一次 [[RACScheduler mainThreadScheduler]afterDelay:5 schedule:^{ NSLog(@"五秒后执行一次"); }];
-
定时执行
//每隔两秒执行一次 //这里要加takeUntil条件限制一下否则当控制器pop后依旧会执行 [[[RACSignal interval:2 onScheduler:[RACScheduler mainThreadScheduler]] takeUntil:self.rac_willDeallocSignal ] subscribeNext:^(id x) { NSLog(@"每两秒执行一次"); }];
代替addTarget
-
详细的使用方法在我写RACSignal时有写,基本技巧就是翻看RAC框架中UI控件的分类基本就可以得知方法
//输出textfiled中的数据,具体的第一篇笔记有详细讲述 [[self.textfiled rac_textSignal] subscribeNext:^(id x) { NSLog(@"%@",x); }];
网友评论
可能是由于ReactiveObjC版本不同吧(我测试的版本:ReactiveObjC 3.1.0),我分别测试了自定义协议和UITableViewDelegate:
1.自定义协议:delegate的设置位置与rac_signalForSelector无关,即放在前后皆可;
2. UITableViewDelegate:不同的代理方法表现也不同:例如scrollViewWillBeginDragging代理方法,则无相关性,放在前后皆可;但tableView:didSelectRowAtIndexPath:则必须放在rac_signalForSelector之后才能生效。
造成原因暂时未知;
而且为了统一,统一放在rac_signalForSelector之后也比较方便记忆且保险。