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
- RAC扩展──异步filter、map
- FILTER&MAP
- filter,map,reduce
- filter,map,reduce
- python:map filter reduce
- filter、map、reduce、lambda
- map,enumerate,zip,filter
- JavaScript "filter" and "map"
- python filter and map
- filter()map() reduce()
- python filter/map/reduce
- filter map reduce
- Python filter map练习
- python filter,map,lambda
- python map filter lambda
- python filter lamda map
- lambda(),map(),reduce(),filter()
- Python filter 和map
- Android 6.0+ 运行时权限——EasyPermissions源码解析
- Linux学习——用户管理命令
- CodeForces 144DMissile Silos
- 203. Remove Linked List Elements
- bzoj [1005] [HNOI2008]明明的烦恼
- RAC扩展──异步filter、map
- 七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)
- czg.sh(烧写SD脚本)
- Skinned Mesh 原理解析和一个最简单的实现示例 作者:n5 Email: happyfirecn##yahoo.com.cn Blog: http://blog.csdn.net/n5
- LintCode | 167. 链表求和
- POJ 2583 Series Determination G++
- 人工智能不仅玩坏了一只猫,还玩坏了整个简笔画
- 在腾讯云上部署Hexo博客
- 科锐课堂笔记:2017/3/14 指针