Signals由RACSignal类表示,继承自RACStream。
先简要说明一下RACStream
streams代表任意的值,其值会随着事件发⽣生变化,由RACStream类表示。值可能马上可用,或者在将来某一段时间可用,但必须按顺序获取,也就是说,在获取到第一个值之前,是不可能获取到第⼆个值。 streams 是⼀一个构造因果关系的结构(Monad),它可以实现在基本的初始值上进⾏行复杂的操作运算(filter,map,reducet等)。 streams不会被经常使⽤用,⼤大多情况下表现为signal和sequences,即Signal和Sequence是由stream继承。
主角signal
Signals一般表示将来被传递的数据。在很多文档中都可以看到就是说signal可以用带代替 Delegate、 Block Callbacks、Target Action、KVO、Notifications。(上篇简要应用中可以看出)当信号接收到数据时,值就会通过signal被发送出去,它推送数据给订阅者。用户必须订阅信号才能获取到它的值。Signals发送3种不同类型的事件给它的订阅者:
1)next:next事件是stream提供了一个新值。而RACStream类的方法也只能在这个值上进行操作运算。和cocoa的集合不同的是,它可以包含一个nil值。
2)error:error事件表示在信号完成之前发生了错误。这个事件包含了一个NSError类型的错误。这个值不会在RACStream类⾥里存储。
3)completed事件:表示信号已经成功地完成了。这个值也不会在RACStream类里存储。Signal的运用和处理
//1.基础运用
//RACSignal 信号类
//冷信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"send signal");
//发送信号
[subscriber sendNext:@"hello signal"];
// return nil;
return [RACDisposable disposableWithBlock:^{
//清空资源用 资源释放 subscriber释放才会调用
NSLog(@"clear");
}];
}];
//热信号
//订阅信号
RACDisposable *dis = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"subcribe signal");
//x 信号发送内容
NSLog(@"%@",x);
}];
//取消订阅
[dis dispose];
//只有 信号被订阅者订阅了 createSignal里面的block才会被触发 这有 信号被发送了 订阅信号里的block才会被触发
//RAC的重要作用就是值传递 所以 信号的创建跟订阅可以不再一个文件里面用于文件间的值传递
//2.定时操作
[[RACSignal interval:2.0 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
//3.延迟操作 delay 延迟2s发送信号
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"adafa");
[subscriber sendNext:@"hello, RAC."];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//超时操作 timeout 2s后视为异常抛出错误
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"hello, RAC."];
return nil;
}] timeout:2.0 onScheduler:[RACScheduler currentScheduler]];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
//节流操作 throttle 信号在2s内没有发生变化则发送,如果发生变化则发送最终信号
[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"create Signal");
[subscriber sendNext:@"test"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"aaa"];
});
return nil;
}]throttle:2]subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
- 信号处理的相关
- 值过滤
- filter: (BOOL (^)(id value))
- takeUntil
RAC中的filter同名方法- filter:(BOOL (^)(id value)),简单明了,将一个value用block做test,返回YES的才会通过,它的内部实现使用了- flattenMap:,将原来的Signal经过过滤转化成只返回过滤值的Signal
- 值过滤
//takeUntil 信号的有效期
//takeUntil:(RACSignal *)
//当给定的signal完成前一直取值。
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"test" object:nil]takeUntil:[RACObserve(self.person, name) filter:^BOOL(id _Nullable value) {
NSString *n = (NSString *)value;
NSLog(@"我是name n = %@",n);
return n.length > 7;
}]] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"x = %@",x);
}];
此外,还有几个这个方法的衍生方法:
- ignore: (id)
忽略给定的值,注意,这里忽略的既可以是地址相同的对象,也可以是- isEqual:结果相同的值,也就是说自己写的Model对象可以通过重写- isEqual:方法来使- ignore:生效。如下:
[[self.inputTextField.rac_textSignal ignore:@"sunny"] subscribeNext:^(NSString *value) {
NSLog(@"`sunny` could never appear : %@", value);
}];
- ignoreValues
这个比较极端,忽略所有值,只关心Signal结束,也就是只取Comletion和Error两个消息,中间所有值都丢弃。
注意,这个操作应该出现在Signal有终止条件的的情况下,如rac_textSignal这样除dealloc外没有终止条件的Signal上就不太可能用到。
- distinctUntilChanged
也是一个相当常用的Filter(但它不是- filter:的衍生方法),它将这一次的值与上一次做比较,当相同时(也包括- isEqual:)被忽略掉。
如果不增加distinctUntilChanged的话对于连续的相同的输入值就会有不必要的处理,这个栗子只是简单的UI刷新,但遇到如写数据库,发网络请求的情况时,代价就不能购忽略了。
所以,对于相同值可以忽略的情况,果断加上。
起止点过滤类型
除了被动的当next值来的时候做判断,也可以主动的提前选择开始和结束条件,分为两种类型:take型(取)和 skip型(跳)
- take: (NSUInteger)
从开始一共取N次的next值,不包括Competion和Error,如:
以此信号为例
//RACSignal 信号类
//冷信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"send signal");
//发送信号
[subscriber sendNext:@"hello signal one"];
[subscriber sendNext:@"hello signal two"];
[subscriber sendNext:@"hello signal three"];
[subscriber sendNext:@"hello signal four"];
// return nil;
return [RACDisposable disposableWithBlock:^{
//清空资源用 资源释放 subscriber释放才会调用
NSLog(@"clear");
}];
}];
//订阅信号 take 取前两个
RACDisposable *dis = [[signal take:2] subscribeNext:^(id _Nullable x) {
NSLog(@"subcribe signal");
//x 信号发送内容
NSLog(@"%@",x);
}];
//取消订阅
[dis dispose];
- takeUntilBlock:(BOOL (^)(id x))
对于每个next值,运行block,当block返回YES时停止取值,如
RACDisposable *dis = [[signal takeUntilBlock:^BOOL(id _Nullable x) {
return [x isEqualToString:@"hello signal three"];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"subcribe signal");
//x 信号发送内容
NSLog(@"%@",x);
} error:^(NSError * _Nullable error) {
NSLog(@"errpr");
} completed:^{
NSLog(@"complete");
}];
“`
- takeWhileBlock:(BOOL (^)(id x))
上面的反向逻辑,对于每个next值,block返回 YES时才取值
- skip:(NSUInteger)
从开始跳过N次的next值,上篇中对textField的值的监听,在首次进入和触发的时候都有响应就可以用这个跳过去啦, skipUntilBlock:(BOOL (^)(id x))
和- takeUntilBlock:同理,一直跳,直到block为YESskipWhileBlock:(BOOL (^)(id x))
和- takeWhileBlock:同理,一直跳,直到block为NO