前面我们说了信号的创建以及它内部实现的一个逻辑。这篇文章开始说一下RAC的场景用法。
Button 监听方法
按照我们系统的button的写法
[self.testbutton addTarget:self action:@selector(testClick:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)testClick:(UIButton *)sender{
}
就像上面的代码,给按钮添加点击事件,如果不实现方法还会报错奔溃。当然也可以用xib或者storyboard来实现。再来看看RAC是怎么实现的。
//通过rac监听按钮
[[self.testbutton rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"按钮输出的是:%@",x);
}];
一行代码搞定,不用担心没实现方法奔溃,很省心啊。我们前面说了,创建信号 发送消息,订阅信号,但是在这没有发送消息,那这个订阅block是怎么触发的。点进方法看看
- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents {
@weakify(self);
return [[RACSignal
createSignal:^(id<RACSubscriber> subscriber) {
@strongify(self);
[self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
RACDisposable *disposable = [RACDisposable disposableWithBlock:^{
[subscriber sendCompleted];
}];
[self.rac_deallocDisposable addDisposable:disposable];
return [RACDisposable disposableWithBlock:^{
@strongify(self);
[self.rac_deallocDisposable removeDisposable:disposable];
[self removeTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
}];
}]
setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", RACDescription(self), (unsigned long)controlEvents];
}
这个方法 创建一个信号,而在block里面,我们看到[self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents]; 这个给订阅者添加了发送消息的方法,而下面创建信号的销毁,在信号销毁的时候移除发送消息方法。这也就可以解释为什么,在button监听中不需要发送消息。
当然除了上面的监听方法,还有其他的
[[self.testbutton rac_signalForSelector:@selector(testClick:)]subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"输出的:%@",x);
}];
监听textfield输入
不适用Rac,平常我们添加textfield内容变化,可以用系统给的delegate也可以给textfield添加方法 查看内容的变化,都很麻烦。现在我们来看看使用rac的代码
[self testTextField];
-(void)testTextField{
[[self.numtextfield rac_textSignal]subscribeNext:^(NSString * _Nullable x) {
NSLog(@"输入的是:%@",x);
self.titlelabel.text=x;
}];
}
真的是一句代码搞定。获取到内容我们就可以在block里面操作。你觉得这样就很简单了嘛。当然不是,rac还有更加简单的。
RAC(self.titlelabel,text)=self.numtextfield.rac_textSignal;
上面的代码同样也能达到我们的结果。
RAC(对象,对象的属性)=(一个信号);
比如RAC(btn,enable)=(RACSignal) 按钮的ennable等于一个信号的
//可以选择想要的状态监听 这里是输入完之后
[[self.numtextfield rac_signalForControlEvents:UIControlEventEditingDidEnd]subscribeNext:^(__kindof UIControl * _Nullable x) {
//x 就是numtextfield本身
UITextField *textField=x;
NSLog(@"输入的是:%@",textField.text);
}];
//添加条件--输入文字长度>10时,调用订阅block
[[self.numtextfield.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
return value.length>10;
}]subscribeNext:^(NSString * _Nullable x) {
NSLog(@"输出的是:%@",x);
}];
这里我们用到一个fillter 这个是过滤,我们把它放在后面说。上面就是textfield的一些基本使用。
KVO
在之前我们的时候,kvo是像下面这样创建的
[self.titlelabel addObserver:self forKeyPath:@"text" options:(NSKeyValueObservingOptionNew) context:nil];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"text"]) {
NSLog(@"---%@",change);
}
}
-(void)dealloc{
[self removeObserver:self forKeyPath:@"text"];
}
先要添加观察,然后在观察对象发生变化时,做出各种操作。当添加多个观察时,需要根据keypath来判断。最后还需要移除观察者。这样写就很麻烦。
下面我们来看看RAC是怎么实现的
[[_titlelabel rac_valuesForKeyPath:@"text" observer:self]subscribeNext:^(id _Nullable x) {
NSLog(@"----%@",x);
}];
再来个简单的
[RACObserve(_titlelabel, text) subscribeNext:^(id _Nullable x) {
NSLog(@"--rac:--%@",x);
}];
相比我们原来创建观察,rac简单多了。
通知
我们先来看看,不用rac是怎么实现的
现在一个界面创建
[[NSNotificationCenter defaultCenter]postNotificationName:@"TestNoti" object:nil userInfo:@{@"name":@"test"}];
然后接受
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(noti:) name:@"TestNoti" object:nil];
}
-(void)noti:(NSNotification *)noti{
}
最后再delloc中移除
[[NSNotificationCenter defaultCenter]removeObserver:self];
而使用RAC的话,我们可以减少add的代码,同时也不需要在delloc中移除通知
[[[NSNotificationCenter defaultCenter]rac_addObserverForName:@"TestNoti" object:nil]subscribeNext:^(NSNotification * _Nullable x) {
NSDictionary *dict=x.userInfo;
NSLog(@"传递参数是:%@",dict);
}];
代理
先来看看不用Rac是怎么写的 总共六步
@protocol TestDelegate <NSObject>
@optional
-(void)testNameWith:(NSString *_Nullable)name;
@end
@interface SecondVC : UIViewController
@property (weak, nonatomic) id<TestDelegate > ldelegate;
@end
-(IBAction)btnclick:(UIButton *)sender{
if ([self.ldelegate respondsToSelector:@selector(testNameWith:)]) {
[self.ldelegate testNameWith:@"123"];
}
上面之写了前三步骤,但看着很繁琐。那么,使用rac又是什么效果呢
//创建信号
@property (strong, nonatomic) RACSubject *btnSubject;
//初始化
-(RACSubject *)btnSubject{
if (!_btnSubject) {
_btnSubject=[RACSubject subject];
}
return _btnSubject;
}
//在传递参数
- (IBAction)registerBtnClick:(UIButton *)sender {
[_btnSubject sendNext:@"传递参数"];
}
//订阅信号
[logintVC.btnSubject subscribeNext:^(id _Nullable x) {
NSLog(@"接受的参数是:%@",x);
}];
现在看看,rac是不是简单多了。
RACCommand
RACCommand在RAC中是对一个动作的触发条件以及它产生的出发事件的封装。
触发条件:初始化RACCommand的入参enabledSignal就决定了是否能开始执行
触发事件:signalblock就是对触发事件的封装。
-(void)testCommend{
RACCommand *command=[[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
NSLog(@"输出为:%@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"猪八戒胖了胖"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁了");
}];
}];
}];
[command execute:@"发送消息了1111"];
}
打印结果:LBDaySurgery(Dev)[14495:5446321] 输出为:发送消息了1111
上面我们能拿到传递的参数@"发送消息了1111",但是 [subscriber sendNext:@"猪八戒胖了胖"];发送的消息,我们怎么拿到呢。
[[command execute:@"发送消息了1111"]subscribeNext:^(id _Nullable x) {
NSLog(@"=======%@",x);
}];
2021-04-12 15:40:43.425053+0800 LBDaySurgery(Dev)[14540:5453960] 输出为:发送消息了1111
2021-04-12 15:40:43.438798+0800 LBDaySurgery(Dev)[14540:5453960] =======猪八戒胖了胖
我们添加了订阅信号,点击进execute方法,就能发现,它返回的是一个信号。既然是信号那就能订阅。最后也成功的打印出内容。
除了上面的方式还有其他的方法可以打印出
RACCommand *command=[[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
NSLog(@"输出为:%@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"猪八戒胖了胖"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁了");
}];
}];
}];
// [[command execute:@"发送消息了1111"]subscribeNext:^(id _Nullable x) {
//
// NSLog(@"=======%@",x);
// }];
[command.executionSignals subscribeNext:^(id _Nullable x) {
NSLog(@"-------%@",x);
[x subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}];
[command execute:@"666 666"];
04-12 15:47:48.573818+0800 LBDaySurgery(Dev)[14546:5456154] 输出为:666 666
2021-04-12 15:47:48.587024+0800 LBDaySurgery(Dev)[14546:5456154] -------<RACDynamicSignal: 0x281487b60> name:
2021-04-12 15:47:48.587084+0800 LBDaySurgery(Dev)[14546:5456154] 猪八戒胖了胖
executionSignals就是用来发送信号的信号源,需要注意的是这个方法一定要在执行execute方法之前,否则就不起作用了.
上面的方法觉得很麻烦,在来看个实现简单的。
RACCommand *command=[[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
NSLog(@"输出为:%@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"猪八戒胖了胖"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁了");
}];
}];
}];
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"++++++%@",x);
}];
[command execute:@"666 666"];
上面这种是不是简练多了。但是 出现了一个switchToLatest,这是有什么用的呢。
switchToLatest:用于信号中信号,通过switchToLatest回去最新的信号。
具体我来段代码就明白了
-(void)testswitchToLatest{
RACSubject *subject1=[RACSubject subject];
RACSubject *subject2=[RACSubject subject];
RACSubject *subject3=[RACSubject subject];
[subject1.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"-----输出是:%@",x);
}];
[subject1 sendNext:subject2];
[subject1 sendNext:subject3];
[subject3 sendNext:@"这个是3"];
[subject2 sendNext:@"这个是2"];
}
91953+0800 LBDaySurgery(Dev)[14676:5484247] -----输出是:这个是3
最后加入的信号是sendNext:subject3,所以它打印出来的就是3的消息参数
RACTuple
RACTuple就是把oc的数组进行了一层封装。
创建方法:
-(void)testRACTuple{
[RACTuple tupleWithObjects:@"123",@666,@"123",@"djiue de", nil];
[RACTuple tupleWithObjectsFromArray:@[@"得救的就",@"99999"]];
[RACTuple tupleWithObjectsFromArray:@[@"232131",@"333334",@"444453"] convertNullsToNils:YES];
}
点进去查看tonil这个是是什么
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count];
for (id object in array) {
[newArray addObject:(object == NSNull.null ? RACTupleNil.tupleNil : object)];
}
用来判断是否为空以及可以做的操作。
RACTuple *tuple=[RACTuple tupleWithObjectsFromArray:@[@"232131",@"333334",@"444453"] convertNullsToNils:YES];
NSLog(@"+++++%@ -----%@=====%@",tuple[0],tuple.first,tuple.last);
打印出:LBDaySurgery(Dev)[14697:5497499] +++++232131 -----232131=====444453
对照NSArray数组的操作,其实都是类似的。
RACSequence
1.可用for in 枚举
2.rac对oc的集合和RACTuple进行Category扩充,可用集合. rac_sequence,把集合快速的转成RACSequence对象。
3.订阅RACSequence的signal,可遍历所有元素。但内部实现是异步的,所以需要注意时间顺序。
下面来看看具体的实现
-(void)testRACSequence{
NSArray *array=@[@"12",@"34",@"56"];
NSDictionary *dict=@{@"name":@"小李子",@"age":@"长生不死",@"socre":@"无穷大"};
NSString *str=@"abc";
NSSet *set=[NSSet setWithArray:array];
RACTuple *tuple=[RACTuple tupleWithObjectsFromArray:array];
//nsarray
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"遍历数组输出的是:%@",x);
}];
//字典
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"字典输出的是---:%@",x);
}];
//字符串遍历
[str.rac_sequence.signal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"字符串:%@",x);
}];
//集合
[set.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"集合:%@",x);
}];
[tuple.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"元祖:%@",x);
}];
}
按照oc的遍历来看,最后打印出来的应该是按顺序的。我们来看下是不是
021-04-12 17:53:27.374930+0800 LBDaySurgery(Dev)[14715:5506387] 遍历数组输出的是:12
2021-04-12 17:53:27.374996+0800 LBDaySurgery(Dev)[14715:5506387] 遍历数组输出的是:34
2021-04-12 17:53:27.375021+0800 LBDaySurgery(Dev)[14715:5506387] 遍历数组输出的是:56
2021-04-12 17:53:27.375081+0800 LBDaySurgery(Dev)[14715:5506389] 元祖:12
2021-04-12 17:53:27.375093+0800 LBDaySurgery(Dev)[14715:5506390] 字符串:a
2021-04-12 17:53:27.375116+0800 LBDaySurgery(Dev)[14715:5506389] 元祖:34
2021-04-12 17:53:27.375145+0800 LBDaySurgery(Dev)[14715:5506389] 元祖:56
2021-04-12 17:53:27.375199+0800 LBDaySurgery(Dev)[14715:5506391] 集合:12
2021-04-12 17:53:27.375256+0800 LBDaySurgery(Dev)[14715:5506383] 字典输出的是---:<RACTwoTuple: 0x282f9f420> (
name,
"\U5c0f\U674e\U5b50"
)
2021-04-12 17:53:27.375273+0800 LBDaySurgery(Dev)[14715:5506390] 字符串:b
2021-04-12 17:53:27.375283+0800 LBDaySurgery(Dev)[14715:5506391] 集合:34
2021-04-12 17:53:27.375385+0800 LBDaySurgery(Dev)[14715:5506390] 字符串:c
2021-04-12 17:53:27.375475+0800 LBDaySurgery(Dev)[14715:5506383] 字典输出的是---:<RACTwoTuple: 0x282f91950> (
age,
"\U957f\U751f\U4e0d\U6b7b"
)
2021-04-12 17:53:27.375542+0800 LBDaySurgery(Dev)[14715:5506391] 集合:56
2021-04-12 17:53:27.375641+0800 LBDaySurgery(Dev)[14715:5506383] 字典输出的是---:<RACTwoTuple: 0x282f918c0> (
socre,
"\U65e0\U7a77\U5927"
)
很明显不是按顺序来的,还记得上面的第3条嘛,它内部是异步执行的。所以它的顺序不是我们想的那样 从上到下执行的。
网友评论