RAC扩展──异步filter、map

来源:互联网 发布:检测 android ios js 编辑:程序博客网 时间:2024/06/06 16:46

一、前言

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
原创粉丝点击