Search code examples
objective-cdesign-patternsuikitreactive-cocoa

Some ReactiveCocoa Design Pattern Questions


Sorry for the multi-question post, but they're all somewhat related. I apologize if some of this is obvious, I'm still trying to wrap my head around ReactiveCocoa.

I have a UIViewController that's being passed a RACSignal whose values it needs to display. This signal will either emit a model object immediately if it already exists on the device, or if the model needs to be fetched, when the fetch finishes; so, basically the signal is a promise. This allows me to remove all knowledge of network from the view controller.

  1. if the user dismisses the view controller, I no longer need whatever the signal will emit. Is this a normal thing to do in the view controller?

    - (void) dealloc
    {
        [_modelSignalDisposable dispose] ; // Dispose of the subscription to the signal
    }
    
  2. Let's say that the device loses its connection while a model fetch is occurring, and this causes the signal to emit an error. In this case I may display something like a reload button to let the user try again. When the user taps the reload button, can I just resubscribe to the same signal even though it's completed? If not, how do I "reset" the signal? Remember, the view controller can't really re-create the signal from scratch since it has no knowledge of how it was created to begin with.

  3. The signal in question is actually a subclass of RACSubject called a Command (has nothing to do with a RACCommand). The idea behind it is that the Command starts network fetching on subscribe and thus overrides -subscribe: to start a network operation. If the view controller goes out of scope due to user interaction I'd like for the subscription disposal to cancel any related fetch operations. Is this the right pattern?

    - (RACDisposable *) subscribe:(id<RACSubscriber>)subscriber
    {
        RACDisposable *rd = [super subscribe:subscriber] ;
        [self.remoteService startFetching] ;
        @weakify(self);
        return [RACDisposable disposableWithBlock:^
            {
                @strongify(self) ;
                [self.remoteService cancelFetching] ;
                [rd dispose] ;
            }] ;
    }
    

Solution

  • if the user dismisses the view controller, I no longer need whatever the signal will emit. Is this a normal thing to do in the view controller?

    Yep, that's totally reasonable. Though I'd use -takeUntil:self.rac_willDeallocSignal instead, so that I don't have to bother with keeping the disposable around.

    Let's say that the device loses its connection while a model fetch is occurring, and this causes the signal to emit an error. In this case I may display something like a reload button to let the user try again. When the user taps the reload button, can I just resubscribe to the same signal even though it's completed? If not, how do I "reset" the signal? Remember, the view controller can't really re-create the signal from scratch since it has no knowledge of how it was created to begin with.

    You can simply re-subscribe if the signal is a cold signal. That is, if the signal does something on subscription. Usually this means you created the signal with +[RACSignal createSignal:].

    The signal in question is actually a subclass of RACSubject called a Command (has nothing to do with a RACCommand). The idea behind it is that the Command starts network fetching on subscribe and thus overrides -subscribe: to start a network operation. If the view controller goes out of scope due to user interaction I'd like for the subscription disposal to cancel any related fetch operations. Is this the right pattern?

    You have the right idea, but you can just use +[RACSignal createSignal:] instead of subclassing RACSubject.