这里新出了一个东东那就是信号.
什么是信号
RAC的核心就是信号,即RACSignal。
信号可以看做是传递信号的工具,当数据变化时,信号就会发送改变的信息,以通知信号的订阅者执行方法。
热/冷信号
默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
自己动手写一个RACSignal
这是一个信号从创建到接收的完整过程,我们接下来看看控制台输出了什么。
2017-12-22 16:03:38.464288+0800 RACText[4582:165620] x = RACText
2017-12-22 16:03:38.464495+0800 RACText[4582:165620] completed
可以看到,创建信号时我们sent了一个signal,在我们订阅subscribeNext时存储在x中的就是这个字符串signal。从这里看出来,不但我们可以给订阅者传递字符串,只要是一个类一个对象我们都可以传递。
另一方面控制台输出了completed说明订阅信号部分的completed块下得方法也被执行了,这是因为饿哦在创建时发送完signal后又发送了一个completed。同理,error下得方法我们也可以这样调用。
信号的处理
map
[[self.textFild.rac_textSignal map:^id(id value) {
NSLog(@"%@", value);
return @2;
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
在TextFild控件中输入good,输出:
2
l
2
la
2
lal
2
lala
2
还是之前那个监听textfild编辑变化的例子,可以看到,当信号被订阅变成热信号后,这里的map构造的映射块value的值就是控件中的字符变化,而订阅者x的值就是映射者的返回值1。
根据这个功能我们就可以对我们监测的东西和我们需求的东西进行转换。比如监听了字符串变化,我们需要的时变化后的字符串长度而不是变化的字符串本身,则可以在map的返回值中返回text.length,就可以实时捕获到字符串长度;甚至做一个映射表,将各个变化进行一对一或者一对多或者多对一的处理。
filter
filter就是过滤,它可以帮助你筛选出你需要的信号变化。
[[self.textFild.rac_textSignal filter:^BOOL(NSString *value) {
return [value length] > 3;
}] subscribeNext:^(id x) {
NSLog(@"x = %@", x);
}];
输入lalalalal,输出:
x = lala
x = lalal
x = lalala
x = lalalal
x = lalalala
x = lalalalal
上述例子是在字符串长度大于3时才会输出变换后的字符串。
take/skip/repeat
take是获取,skip是跳过,这两个方法后面跟着的都是NSInteger。所以take 2就是获取前两个信号,skip 2就是跳过前两个。repeat是重复发送信号。
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
[subscriber sendNext:@"4"];
[subscriber sendNext:@"5"];
[subscriber sendCompleted];
return nil;
}] take:2];
[signal subscribeNext:^(id x) {
NSLog(@"%@", x);
}completed:^{
NSLog(@"completed");
}];
这个demo只会输出前两个信号1和2还有完成信号completed,skip,repeat同理。
相似的还有takeLast takeUntil takeWhileBlock skipWhileBlock skipUntilBlock repeatWhileBlock都可以根据字面意思来理解。
** delay**
延时信号,顾名思义,即延迟发送信号。
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"delay"];
[subscriber sendCompleted];
return nil;
}] delay:2];
NSLog(@"tag");
[signal subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
输出:
tag
delay
延迟了2秒才收到信号打印出x的值
** throttle**
节流,在我们做搜索框的时候,有时候需求的时实时搜索,即用户每每输入字符,view都要求展现搜索结果。这时如果用户搜索的字符串较长,那么由于网络请求的延时可能造成UI显示错误,并且多次不必要的请求还会加大服务器的压力,这显然是不合理的,此时我们就需要用到节流。
[[[self.textFild rac_textSignal] throttle:0.5] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
加了节流管道,后面跟上了类型为NSTimeInterval的参数后,只有0.5S内信号不产生变化才会发送请求,这样快速的输入也不会造成多次输出。
** distinctUntilChanged**
网络请求中为了减轻服务器压力,无用的请求我们应该尽可能不发送。distinctUntilChanged的作用是使RAC不会连续发送两次相同的信号,这样就解决了这个问题。
[[[self.textFild rac_textSignal] distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
timeout
超时信号,当超出限定时间后会给订阅者发送error信号。
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
[subscriber sendNext:@"delay"];
[subscriber sendCompleted];
}];
return nil;
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@", x);
} error:^(NSError *error) {
NSLog(@"%@", error);
}];
输出:
RACTest[1604:76716] Error Domain=RACSignalErrorDomain Code=1 "The operation couldn’t be completed. (RACSignalErrorDomain error 1.)"
由于在创建信号是限定了延迟3秒发送,但是加了timeout2秒的限定,所以这一定是一个超时信号。这个信号被订阅后,由于超时,不会执行订阅成功的输出x方法,而是跳到error的块输出了错误信息。timeout在用RAC封装网络请求时可以节省不少的代码量。
** ignore**
忽略信号,指定一个任意类型的量(可以是字符串,数组等),当需要发送信号时讲进行判断,若相同则该信号会被忽略发送。
[[[self.textFild rac_textSignal] ignore:@"good"] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
慢慢写你也会的