RAC扩展──异步filter、map

3 篇文章 0 订阅

一、前言

RAC有非常丰富的Operation,可以让我们的开发事半功倍。常用的比如:filter、map。但是原生的filter、map要求我们在Block同步返回结果。但是,有的时候,我们只能异步返回结果。比如我们需要根据用户的输入进行filter(二次确认);比如我们需要先请求网络才能进行map。

所以,我对原有的Operation进行了扩展,开发了asyncFilter、asyncMap两个新的Operation。


二、使用方法

asyncFilter、asyncMap的入参类型是void (^)(id value, id<RACSubscriber> subscriber)的Block,与原始filter、map直接return结果不同,asyncFilter、asyncMap通过subscriber将结果发送出来。asyncFilter在block中[subscriber sendNext:@(YES)]; / [subscriber sendNext:@(NO)];,asyncMap在block中[subscriber sendNext:yourMappedValue];。注意发送error事件会导致整个observe结束,我并没有做防护,因为考虑到调用方在遇到异常情况的时候,可能需要直接结束整个observe。


三、实现思路

因为异步了,filter、map Block都不会直接返回结果了,结果将会通过一个subscriber返回(这个subscriber是Block的入参,Operation是会塞给Block),此时这个Block也就变成了一个数据源

内部是把原Signal flattenMap成新的Signal,新的Signal的数据源就是这个Block(把这个Block罩个壳就是新Signal)。

我们知道,flattenMap会把原Signal的每一个value都map成一个新的Signal,在我们的场景里,新的Signal一定只有一个value,所以我asyncFilter、asyncMap两个Operation接收到一个值的时候会自动complete,调用方在发送@(YES)/@(NO)/@(mappedValue)之后不必再手动发送一个complete事件。及时complete掉Signal,dispose掉Signal,提升效率。

1. asyncFilter

主体是flattenMap,构建新的Signal,新的Signal的数据源就是filterBlock,然后对新的Signal就行变换——先filter掉为NO的值,之后map回原来的值。

2. asyncMap

主体是flattenMap,返回新的Signal,新的Signal的数据源就是mapBlock,直接把值传递下去。


四、使用示例

设想一个业务场景: 选中一批订单=>选择一个用户=>二次确认是否要把订单移交给这个用户。选择一个用户这一步骤使用了asyncMap,二次确认使用了asyncFilter。

-(RACSignal *)transferOrdersSignal{
    return [[[[[self selectedOrdersSignal]
             st_asyncMap:^(NSDictionary *selectedOrdersParams, id<RACSubscriber> subscriber) {
                 [[self selectedCustomerSignal]
                          subscribeNext:^(NSString *selectedCustomer) {
                              if (selectedCustomer == nil) {
                                  [subscriber sendCompleted];
                              } else {
                                  NSMutableDictionary *parmas = [selectedOrdersParams mutableCopy];
                                  [parmas setValue:selectedCustomer forKey:@"targetUserId"];
                                  [subscriber sendNext:[parmas copy]];
                              }
                          }];
             }]
             st_asyncFilter:^(NSDictionary *params, id<RACSubscriber> subscriber) {
                 NSNumber *orderCount = params[@"orderCount"];
                 AlertView *alertView = [[AlertView alloc]
                                           initWithmessage:[NSString stringWithFormat:@"是否确定移交此%@笔订单", orderCount]
                                           cancelTitle:@"取消"
                                           cancleColor:[UIColor whiteColor]
                                           otherTitle:@"确定"
                                           otherColor:[UIColor colorWithRGB:0xff9800]
                                           clickIndexHandle:^(NSInteger index) {
                                               if(index == 0){
                                                   [subscriber sendNext:@(NO)];
                                               } else {
                                                   [subscriber sendNext:@(YES)];
                                               }
                                           }];

                 [alertView show];
             }]
             flattenMap:^RACStream *(NSDictionary *params) {
                 //web request
             }]
             doError];
}

五、源码

- (instancetype)st_asyncFilter:(void (^)(id value, id<RACSubscriber> subscriber))block{
    return [self flattenMap:^RACStream *(id actualValue) {
            return [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                                                block(actualValue, subscriber);
                                                return nil;
                                            }] take:1
                                             ] filter:^BOOL(id filterFlagValue) {
                                                return [filterFlagValue boolValue];
                                            }] map:^id(id value) {
                                                return actualValue;
                                            }];
    }];
}

- (instancetype)st_asyncMap:(void (^)(id value, id<RACSubscriber> subscriber))block{
    return [self flattenMap:^RACStream *(id value) {

        return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                    block(value, subscriber);
                    return nil;
                }] take:1];;
    }];
}

六、Update 2017-2-8

内部换了一种实现。采用了自定义的一次性信号── STOneTimeSignal。

@implementation RACSignal (STExtension)

- (instancetype)st_asyncFilter:(void (^)(id value, id<RACSubscriber> subscriber))block{
    return [self flattenMap:^RACStream *(id value) {
        return [[STOneTimeSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                                                block(value, subscriber);
                                                return nil;
                                            }]
                                   flattenMap:^RACStream *(id flag) {
                                       if ([flag boolValue]) {
                                           return [RACSignal return:value];
                                       } else {
                                           return [RACSignal empty];
                                       }
                                   }];
    }];
}

- (instancetype)st_asyncMap:(void (^)(id value, id<RACSubscriber> subscriber))block{
    return [self flattenMap:^RACStream *(id value) {
        return [STOneTimeSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                                block(value, subscriber);
                                return nil;
                            }];
    }];
}

一次性信号── STOneTimeSignal的实现。STOneTimeSignal主要依赖STOneTimeSubscriber。

@interface STOneTimeSignal : RACDynamicSignal

@end
@implementation STOneTimeSignal

//Override subscribe method, use STOneTimeSubscriber to replace RACSubscriber
//And make sure custom subscribe method get called

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCAssert(NO, @"This method is not implemented yet");
    return nil;
}

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(completedBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:nextBlock error:NULL completed:completedBlock];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);
    NSCParameterAssert(completedBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock {
    NSCParameterAssert(errorBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:NULL error:errorBlock completed:NULL];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock {
    NSCParameterAssert(completedBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:NULL error:NULL completed:completedBlock];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:nextBlock error:errorBlock completed:NULL];
    return [super subscribe:o];
}

- (RACDisposable *)subscribeError:(void (^)(NSError *))errorBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(completedBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);

    //把外部Subscriber转化为OneTimeSubscriber
    STOneTimeSubscriber *o = [STOneTimeSubscriber subscriberWithNext:NULL error:errorBlock completed:completedBlock];
    return [super subscribe:o];
}


@end

STOneTimeSubscriber的实现。


@interface STOneTimeSubscriber : NSObject <RACSubscriber>

+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed;

@end

@interface STOneTimeSubscriber ()

//...

@end

@implementation STOneTimeSubscriber

//...

#pragma mark RACSubscriber

- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);

        //complete automatically when receive value, that's why this's called one-time subscriber.
        //you can accomplish the same function using `take` operation. but that's more expensive
        [self sendCompleted];
    }
}

//...

@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值