首页 > 代码库 > 让RAC支持进度消息
让RAC支持进度消息
我们在使用RAC的时候,有时候处理一个主消息之外可能还需要其他的辅助消息。比如说,我们在上次图片或者下载的时候。往往除了需要知道结果,还需要过程的进度。简单的做法就是外部自己创建一个subject,然后给具体做事情的模块来手动设置subject的next值了。这是一个经常用的东西,所以我这边参考了AFNetworking+RACExtension中得代码。自己重建了支持进度的signal和subscribe。我是在RAC 2.4.2上面搞的。所以不一定支持其他版本的哦。 废话不说,直接上代码。
// // RACSubscriber+KLProgressSupport.h // KoalaUtilKit // // Created by Tommy on 15/1/8. // Copyright (c) 2015年 Koala Team. All rights reserved. // #import "ReactiveCocoa.h" @interface KLRACSubscriber: NSObject<RACSubscriber> + (instancetype)subscriberWithNext:(void (^)(id x))next progress:(void (^)(float progress))progress error:(void (^)(NSError *error))error completed:(void (^)(void))completed; - (void)sendProgress:(float)p; - (void)sendNext:(id)value; - (void)sendError:(NSError *)error; - (void)sendCompleted; - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable; @end @interface RACSignal (KLProgressSubscriptions) // Convenience method to subscribe to the `progress` and `next` events. - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock ; // Convenience method to subscribe to the `progress`, `next` and `completed` events. - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock; // Convenience method to subscribe to the `progress`, `next`, `completed`, and `error` events. - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress completed:(void (^)(void))completedBlock; // Convenience method to subscribe to `progress`, `next` and `error` events. - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock; // Convenience method to subscribe to `progress`, `error` and `completed` events. - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; @end @interface RACSubject (KLProgressSending) - (void)sendProgress:(float)value; @end
// // RACSubscriber+KLProgressSupport.m // KoalaUtilKit // // Created by Tommy on 15/1/8. // Copyright (c) 2015年 Koala Team. All rights reserved. // #import "RACSubscriber+KLProgressSupport.h" #import "RACPassthroughSubscriber.h" #import <objc/runtime.h> #import "KLLog.h" @interface RACPassthroughSubscriber (KLProgress) - (void)sendProgress:(float)p; @end @implementation RACPassthroughSubscriber(KLProgress) - (void)sendProgress:(float)p{ RACDisposable *disposable = [self performSelector:@selector(disposable)]; if (disposable.disposed) return; id<RACSubscriber> innerSubscriber = [self valueForKey:@"innerSubscriber"]; if([innerSubscriber isKindOfClass:[RACPassthroughSubscriber class]]){ [(RACPassthroughSubscriber*)innerSubscriber sendProgress:p]; }else if([innerSubscriber isKindOfClass:[KLRACSubscriber class]]){ [(KLRACSubscriber*)innerSubscriber sendProgress:p]; }else{ NSAssert(0, @"not recognized object"); } } @end static NSString *KLProgress_Block_Key; @interface KLRACSubscriber() @property(nonatomic,strong)id<RACSubscriber> subscriber; @property (nonatomic, copy) void (^_progress)(float progress); @end @implementation KLRACSubscriber + (instancetype)subscriberWithNext:(void (^)(id x))next progress:(void (^)(float progress))progress error:(void (^)(NSError *error))error completed:(void (^)(void))completed { Class subscriberCls = NSClassFromString(@"RACSubscriber"); SEL createSel = sel_registerName("subscriberWithNext:error:completed:"); static int supportCreate = -1; id<RACSubscriber> proxySubscriber = nil; void *obj = nil; if(-1 == supportCreate){ supportCreate = [subscriberCls respondsToSelector:createSel]; } if(YES == supportCreate){ NSMethodSignature *sig= [subscriberCls methodSignatureForSelector:createSel]; if(sig && !strcmp(sig.methodReturnType, @encode(id))){ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; [invocation setTarget:subscriberCls]; [invocation setSelector:createSel]; next = [next copy]; error = [error copy]; completed = [completed copy]; [invocation setArgument:&next atIndex: 2]; [invocation setArgument:&error atIndex: 3]; [invocation setArgument:&completed atIndex: 4]; [invocation retainArguments]; [invocation invoke]; [invocation getReturnValue:&obj]; proxySubscriber = (__bridge id<RACSubscriber>)(obj); } } KLRACSubscriber *subscriber = nil; if(proxySubscriber){ subscriber = [[KLRACSubscriber alloc]init]; subscriber.subscriber = proxySubscriber; subscriber._progress = progress; }else{ NSAssert(0, @"not create RACSubscriber"); } return subscriber; } - (void)set_progress:(void (^)(float))_progress { objc_setAssociatedObject(self, &KLProgress_Block_Key, _progress, OBJC_ASSOCIATION_COPY); } - (void (^)(float))_progress { return objc_getAssociatedObject(self, &KLProgress_Block_Key); } - (void)sendProgress:(float)p { [[self performSelector:@selector(disposable)] dispose]; if (self._progress != NULL) self._progress(p); } - (void)sendNext:(id)value{ return [self.subscriber sendNext:value]; } - (void)sendError:(NSError *)error{ return [self.subscriber sendError:error]; } - (void)sendCompleted{ return [self.subscriber sendCompleted]; } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable{ [self.subscriber didSubscribeWithDisposable:disposable]; } - (void)forwardInvocation:(NSInvocation *)invocation{ NSAssert(self.subscriber, @"subscriber is nil"); if(!self.subscriber) KLLogError(@"subscriber is nil"); [invocation invokeWithTarget:self.subscriber]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ NSAssert(self.subscriber, @"subscriber is nil"); if(!self.subscriber) KLLogError(@"subscriber is nil:%@",NSStringFromSelector(sel)); NSObject* tmpSub = self.subscriber; return [tmpSub methodSignatureForSelector:sel]; } - (void)dealloc{ self.subscriber = nil; } @end @implementation RACSignal (KLProgressSubscriptions) - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock { NSParameterAssert(progress != NULL); NSParameterAssert(nextBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:nextBlock progress:progress error:NULL completed:NULL]; return [self subscribe:o.subscriber]; } - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock { NSParameterAssert(progress != NULL); NSParameterAssert(nextBlock != NULL); NSParameterAssert(completedBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:nextBlock progress:progress error:NULL completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock { NSParameterAssert(progress != NULL); NSParameterAssert(nextBlock != NULL); NSParameterAssert(errorBlock != NULL); NSParameterAssert(completedBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:nextBlock progress:progress error:errorBlock completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress completed:(void (^)(void))completedBlock { NSParameterAssert(progress != NULL); NSParameterAssert(completedBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:NULL progress:progress error:NULL completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress next:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock { NSParameterAssert(progress != NULL); NSParameterAssert(nextBlock != NULL); NSParameterAssert(errorBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:nextBlock progress:progress error:errorBlock completed:NULL]; return [self subscribe:o]; } - (RACDisposable *)subscribeProgress:(void (^)(float progress))progress error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock { NSParameterAssert(progress != NULL); NSParameterAssert(errorBlock != NULL); NSParameterAssert(completedBlock != NULL); KLRACSubscriber *o = [KLRACSubscriber subscriberWithNext:NULL progress:progress error:errorBlock completed:completedBlock]; return [self subscribe:o]; } @end @implementation RACSubject (KLProgressSending) - (void)sendProgress:(float)value { void (^subscriberBlock)(id<RACSubscriber> subscriber) = ^(id<RACSubscriber> subscriber){ if([subscriber isKindOfClass:[RACPassthroughSubscriber class]]){ [(RACPassthroughSubscriber*)subscriber sendProgress:value]; } }; SEL performBlockSel = sel_registerName("enumerateSubscribersUsingBlock:"); if([self respondsToSelector:performBlockSel]){ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [self performSelector:performBlockSel withObject:subscriberBlock]; #pragma clang diagnostic pop }else{ NSAssert(0, @"not found enumerateSubscribersUsingBlock:"); } } @end
让RAC支持进度消息
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。