RAC学习应用篇--基础应用篇(二)--signal

本文深入探讨RACSignal,它是RACStream的子类,用于表示未来的数据。Signal作为Delegate、Block回调等的替代,通过订阅推送数据给观察者。文章详细介绍了Signal的next、error和completed事件,并讲解了如何使用filter、ignore、distinctUntilChanged等方法进行值过滤和处理。同时,还讨论了take和skip系列方法在确定信号开始和结束条件时的作用。
摘要由CSDN通过智能技术生成

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为YES

  • skipWhileBlock:(BOOL (^)(id x))
    和- takeWhileBlock:同理,一直跳,直到block为NO

摘录参考文档:
iOS函数响应式编程框架ReactiveCocoa概览
Reactive Cocoa详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值