Using RACCommand with MVVM pattern, sending parameters to ViewModel

1.3k views Asked by At

I'm using ReactiveCocoa framework at my app for the power using MVVM design pattern.

So for every Controller, I have a ViewModel. and the Controller is binded to his ViewModel.

UIButton binding will look like so:

@implementation HomeController

-(void) bindViewModel {
 self.viewHeader.buttonSide.rac_command = self.viewModel.execiteFullPortfolio;
}

It all works well, But when i would like to pass parameters to the ViewModel, I'm not sure what is the right way to do so...

Say I have a UICollectionView of Stocks, and every click on a specific stock, I would like to navigate to thats stocks profile page. That logic should be done at the ViewModel, But how do i get the stock passed with the RACCommand?

What I'm currently doing is :

@implementation HomeController
-(void) bindViewModel {
 __unsafe_unretained HomeController *weakSelf = self;
self.viewPortfolioPusherView.scrollGainView.blockSelect = ^ (STStock *stock){
        weakSelf.viewModel.selectedStock = stock;
        [weakSelf.viewModel.executeGoToStock execute:[RACSignal empty]];
    };

}


@implementation HomeViewModel
-(void) initialization {
  self.executeGoToStock = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        dispatch_async(dispatch_get_main_queue(), ^{
        [weakSelf moveToSelectedStock];
        });
        return [RACSignal empty];
    }];
}
-(void) moveToSelectedStock {
    [self stockProfileControllerLazy];
    self.stockProfileController.stock = self.selectedStock;
    [Navigator pushController:self.stockProfileController fromController:[self.delegate controller]];
}

I'm sure this is not best practice! So I'm asking, What is??

Thanks .

1

There are 1 answers

0
jhosteny On BEST ANSWER

Why not just pass the STStock instance into the call to execute on the command, rather than an empty signal?

[weakSelf.viewModel.executeGoToStock execute:stock];

Then:

self.executeGoToStock = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(STStock *stock) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf moveToSelectedStock:stock];
        });
        return [RACSignal empty];
}];

You obviously need to modify moveToSelectedStock to take a parameter as well. However, I'd go a bit further an implement an RACCommand on your Navigator that does that. Furthermore, I'd make a separate view model for an instance of STStock rather than a collection. So, when you select a stock, it might look something a little more like this:

StockViewModel *viewModel = [[StockViewModel alloc] initWithStock:stock];
[[Navigator pushViewModel] execute:viewModel];

This obviously omits a few details. For example, my navigator maps view model classes to controller classes. When a view model is pushed, it creates the corresponding controller, and binds the view model to it.