Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding forward and reverse map operations to RACChannel #1069

Closed
olegam opened this issue Jan 21, 2014 · 2 comments
Closed

Adding forward and reverse map operations to RACChannel #1069

olegam opened this issue Jan 21, 2014 · 2 comments
Labels

Comments

@olegam
Copy link

@olegam olegam commented Jan 21, 2014

I'm still fairly new to the RACChannel thing, but it looks really good. One thing I would like to do to, but I don't know how is to chain in map operations.

For example I have a User class that implements NSCoding. I would like to automatically persist the currentUser property to NSUserDefaults using the NSUserDefaults (RACSupport) category.

If I just do something like

RACChannelTo(self, currentUser) = [defaults rac_channelTerminalForKey:kCurrentUserDefaultsKey];

then my object is never transformed to NSData so I get an exception. Hence I would like to have a forward mapping block that uses NSKeyedUnarchiver to map from NSData to a User object and have a backwards mapping block that maps my User object to NSData using an NSKeyedArchiver.

Is this possible somehow?

@Coneko
Copy link
Member

@Coneko Coneko commented Jan 21, 2014

Terminals are signals and subscribers, so you can use any of the signal methods on them.

Unfortunately

RACChannelTo(self, currentUser) = [defaults rac_channelTerminalForKey:kCurrentUserDefaultsKey];

is pretty opaque, so, but if you look in RACKVOChannel.m the magic is demystified:

- (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key {
    NSCParameterAssert(otherTerminal != nil);

    RACChannelTerminal *selfTerminal = [self objectForKeyedSubscript:key];
    [otherTerminal subscribe:selfTerminal];
    [[selfTerminal skip:1] subscribe:otherTerminal];
}

this means in your case:

RACChannelTerminal *currentUserTerminal = RACChannelTo(self, currentUser);
RACChannelTerminal *defaultsTerminal = [defaults rac_channelTerminalForKey:kCurrentUserDefaultsKey];

[defaultsTerminal subscribe:currentUserTerminal];
[[currentUserTerminal skip:1] subscribe:defaultsTerminal];

at which point you can map back and forth like this:

RACChannelTerminal *currentUserTerminal = RACChannelTo(self, currentUser);
RACChannelTerminal *defaultsTerminal = [defaults rac_channelTerminalForKey:kCurrentUserDefaultsKey];

[[defaultsTerminal map:^(id user){
    return [NSKeyedArchiver archivedDataWithRootObject:user];
} subscribe:currentUserTerminal];
[[[currentUserTerminal skip:1] map:^(NSData *data){
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}] subscribe:defaultsTerminal];

Sorry for the longwinded explanation, give a man a fish and all that.

@olegam
Copy link
Author

@olegam olegam commented Jan 21, 2014

That's awesome! Thanks you so much. I had to make a few minor changes to get it right (a missing bracket and swapped archiver and unarchiver). This works for me:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
RACChannelTerminal *currentUserTerminal = RACChannelTo(self, currentUser);
RACChannelTerminal *defaultsTerminal = [defaults rac_channelTerminalForKey:kCurrentUserDefaultsKey];

[[[defaultsTerminal ignore:nil] map:^(NSData *data) {
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}] subscribe:currentUserTerminal];

[[[currentUserTerminal skip:1] map:^(FIBUser *user){
    return [NSKeyedArchiver archivedDataWithRootObject:user];
}] subscribe:defaultsTerminal];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.