Best Practice for RACSignal Toolkit

I have been instructed to add some instrumental logic to the application to track the delay of various API calls. I'm struggling to come up with a clean, non-side effect to add temporary tools to methods that return RACSignal (deferred execution API calls).

Questions

  • Using ReactiveCocoa @ 1.9.5 (unable to update at this time)
  • Using Parse-RACExtensions @ 0.0.2
  • I would prefer to configure timings at the ViewModel level, rather than modifying Parse-RACExtensions. This is due to the fact that the virtual machine has additional information that I would like to register, for example, request parameters, and I do not need every API.
  • Record timings after receiving completed event
  • In the spirit of painless instrumentation, the burden on the caller should be as small as practical

Attempt to solve

The only thing I could come up with was to create a specific subclass of RACSubscriber that handles the timer logic. Besides the unpleasant subclass, this is obviously not ideal, since it requires an explicit subscribe: which in turn requires replay for the original signal. In addition, there is a burden for the caller, as they must at least refactor to obtain a temporary signal descriptor.

 @interface SignalTimer : RACSubscriber @property (nonatomic) NSDate *startDate; @end @implementation SignalTimer - (void)didSubscribeWithDisposable:(RACDisposable *)disposable { [super didSubscribeWithDisposable:disposable]; self.startDate = [NSDate date]; } - (void)sendCompleted { NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:self.startDate]; NSLog(@"Time elapsed: %f", duration); [super sendCompleted]; } @end 

Usage will look like this:

 - (RACSignal*)saveFoo:(Foo*)fooParseObj { RACSignal *save = [[fooParseObj rac_save] replay]; // Don't forget replay! [save subscribe:[[SignalTimer alloc] initWithName@ "Saving the user foo object"]]; return save; } 

Obviously, I am not happy with this implementation.

Final thoughts

Ideally, I need a method like a chain, but I was not sure how to do it / if I could handle a cold signal without unpleasant side effects inside the category method (for example, calling replay on the receiver).

 [[[fooParseObj rac_save] logTimingsWithName:@"Saving the user foo object"] subscribeNext:...]; 

Thoughts?

+7
ios objective-c reactive-programming reactive-cocoa
source share
1 answer

So I think that I did it a lot harder than necessary. The solution of the following category seems much more idiomatic, but I would like to receive any feedback.

 @interface RACSignal (Timing) - (instancetype)logTimingWithName:(NSString*)name; @end @implementation RACSignal (Timing) - (instancetype)logTimingWithName:(NSString*)name { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSDate* startDate = [NSDate date]; return [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:startDate]; NSLog(@"%@: %f sec", name, duration); [subscriber sendCompleted]; }]; }]; } @end 
+2
source share

All Articles