7
\$\begingroup\$

I have a localization manager class which can change app language on the fly. It's using ReactiveCocoa and my main concern is that I'm not using some of RAC parts correctly.

First (in - (void)configureSignals):

+ (instancetype)sharedInstance
{
    static i2KRLMLocalizationManagerObject *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[[self class] alloc] init];
        [sharedInstance initialConfiguration];
    });
    return sharedInstance;
}

- (void)initialConfiguration
{
    [self configureSignals];
    [self configureAppLocalizations];
}

- (void)configureSignals
{
    RACReplaySubject *subject = [RACReplaySubject replaySubjectWithCapacity:1];
    self.localeConnection = [subject multicast:subject];
    [self.localeConnection autoconnect];

    RACReplaySubject *languagesSubject = [RACReplaySubject replaySubjectWithCapacity:1];
    self.languageNamesConnection = [languagesSubject multicast:languagesSubject];
    [self.languageNamesConnection autoconnect];

    RACReplaySubject *languageIndexSubject = [RACReplaySubject replaySubjectWithCapacity:1];
    self.languageIndexConnection = [languageIndexSubject multicast:languageIndexSubject];
    [self.languageIndexConnection autoconnect];
}

It feels for me that multicast should be used differently(and is used wrong currently, although it works), although I'm not sure how to use it correctly.

Those signals are used to propagate NSLocale, array of supported languages and current language index in that array. I use multicast so that if there is more then 1 subscriber, signal will be shared and current values will be just replayed. I'm not sure that signal multicasting itself is idiomatic/correct way. Also I'm not completely sure if connection is needed at all or I can just go with ReplaySubject.

Second (like here):

- (void)changeToLocale:(NSLocale *)locale
{
    [self reloadBundleWithLocaleID:[locale localeIdentifier]];
    [(RACSubject *)[self localeSignal] sendNext:locale];
}

Cast has to be made now because in interface it's declared as - (RACSignal *)localeSignal; and is actually

- (RACSignal *)localeSignal
{
    return self.localeConnection.signal;
} 

which is defined as RACSignal in ReactiveCocoa as well, but since it's definitely RACSubject(RACReplaySubject is subclass of RACSubject and since sendNext is available on RACSubject and not on RACSignal I need to cast to avoid compiler complaints).

I use that getter instead of self.languageNamesConnection.signal because if I ever change this to something I wouldn't have to go all over and remove traces of that. But the cast looks just wrong.

I don't like this cast at all, although not sure how to improve this(since I'm sending values through multicasted signal; and probably get rid of this sending altogether if possible).

Also general suggestions on improving would be very helpful(I think there should be more FRP way to do this).

Full repo with example is here, class is here.

\$\endgroup\$
3
\$\begingroup\$

Excerpts from answers to my question on RAC repo:

For the first question -

Subjects are naturally multicasted, so you could replace the multicast connection property with @property RACReplaySubject *localeSubject and subscribe directly to that in place of localeSignal.

So there's no need to use connection here.

For the second part - it's enough to have RACSignal in interface and RAC(Replay)Subject in the implementation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.