Reputation: 6475
So I have this BaseCell
class which also has this BaseCellViewModel
. Of course on top of this lives some FancyViewController
with FancyViewModel
. The case here is that BaseCell
has UIButton
on it which triggers this IBAction
method - that's fine and that's cool as I can do whatever I want there, but... I have no idea how should I let know FacyViewController
about the fact that some action happened on BaseCell
.
I can RACObserve
a property in FancViewModel
as it has NSArray
of those cell view models, but how to monitor actual action and notify about exact action triggered on cell?
First thing that came to my mind is the delegation or notifications, but since we have RAC in our project it would be totally stupid not to use it, right?
So, it turns out youc can use RACCommand
to actually handle UI events on specific button. In that case I've added:
@property (strong, nonatomic) RACCommand *showAction;
to my BaseCellViewModel
with simple implementation like:
- (RACCommand *)showAction {
return [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"TEST");
return [[RACSignal empty] logAll];
}];
}
And following this pattern I had to do something in my BaseCell
which turned out to be quite simple and I ended up with adding:
- (void)configureWithViewModel:(JDLBasePostCellViewModel *)viewModel {
self.viewModel = viewModel;
self.actionButton.rac_command = self.viewModel.showAction;
}
And... It works! But...
I need to present UIActionSheet
whenever this happens and this can be show only when I need the current parentViewController
and since I don't have this kind of information passed anywhere I don't know what to do right now.
FancyViewModel
holds a private @property (nonatomic, strong) NSMutableArray <BaseCellViewModel *> *cellViewModels;
, but how can I register something on FancyViewController
to actually listen for execution of RACCommand
on BaseCellViewModel
?
Upvotes: 4
Views: 1403
Reputation: 7944
As you already have a RACCommand
in BaseCellViewModel
, you can use one of its convenience signals. For example, you can track its state using executing
signal:
[baseCellViewModel.showAction.executing subscribeNext:^(NSNumber *executing) {
//do something if the command is executing
}];
Bindings with RACObserve
will work as well, if you need them.
You can also get the latest value from the command's underlying signal (but in the code you posted it won't work, as you use [RACSignal empty]
with doesn't send any 'next' values):
[[baseCellViewModel.command.executionSignals switchToLatest] subscribeNext:^(id x) {
//do something with the value
}];
Note that you should subscribe to this signals when you create BaseCellViewModel
, not in configureWithViewModel
as the latter will be called many times (resulting in many subscriptions for the same signal).
Upvotes: 0
Reputation: 1222
UITableViewCell are volatile, reusable components. They come and go, and your button will do as well.
How about following @danh suggestion and once control is in View Controller, formulate a RAC signal programmatically.
Since I feel rather belonging to RxSwift camp :) I cannot provide source snippet, but this answer is probably what I meant.
Upvotes: 0
Reputation: 62676
There are a few ways that the cell might communicate with the view controller. A common on is via delegation. Have the cell declare a public delegate, like:
// BaseCell.h
@protocol BaseCellDelegate;
@interface BaseCell : UITableViewCell
@property(nonatomic, weak) id<BaseCellDelegate> delegate;
// ...
@end
@protocol BaseCellDelegate <NSObject>
- (void)baseCell:(BaseCell *)cell didReceiveAction:(NSString *)actionName;
@end
When the button is pressed, work out what you'd like to tell the delegate, and tell it:
// BaseCell.m
- (IBAction)buttonWasPressed:(id)sender {
self.delegate baseCell:self didReceiveAction:@"someAction";
}
Then, in the view controller, declare that you conform to the protocol:
// FancyViewController.m
@interface FancyViewController () <BaseCellDelegate>
in cellForRowAtIndexPath
, set the cell's delegate:
// dequeue, etc
cell.delegate = self;
You'll now be required to implement this in the vc:
- (void)baseCell:(BaseCell *)cell didReceiveAction:(NSString *)actionName {
// the cell got an action, but at what index path?
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// now we can look up our model at self.model[indexPath.row]
}
Upvotes: 1