0

I have a button on navigation bar, that named "Edit". And a UICollectionView show with some content. To click the "Edit" button will make into a "EditMode", and the button's title become "Done", the UICollectionView's cell should also updated. Click the "Done" button will do the reverse.

I have write the code bellow: Now after click the "Edit"|"Done" button, the hole collection View will be updated with a refresh, since there's images in the cell get from service which I don't update them. I prefer just update the icon by Cell's signal. but How to refactor the code?

1.viewController's -(void)viewDidLoad

 [[[[self.editButton rac_signalForControlEvents:UIControlEventTouchUpInside]
    doNext:^(UIButton *sender) {
        if ([sender.titleLabel.text isEqualToString:@"Edit"]) {
            [sender setTitle:@"Done" forState:UIControlStateNormal];
        }else{
            [sender setTitle:@"Edit" forState:UIControlStateNormal];
        }
    }]
    flattenMap:^RACStream *(UIButton *sender) {
        BOOL isEditMode = [sender.titleLabel.text isEqualToString:@"Edit"];
        return [RACSignal return:@(isEditMode)];
    }] subscribeNext:^(NSNumber* x) {
        [self.viewModel setEditMode:x.boolValue];
    }];

  // Binding to view model
  [[RACObserve(self.viewModel, dataArray) 
     deliverOnMainThread] subscribeNext:^(id x) {
         @strongify(self);
         [self.collectionView reloadData];
     }];

2.1.viewController's ViewModel's property

 @property (nonatomic, assign, getter= isEditMode) BOOL editMode;

2.2.viewController's ViewModel's -(id)init

  self.isEditModeSignal = RACObserve(self, isEditMode);

3.viewController's - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

  DataModel* item = [self.dataArray objectAtIndex:indexPath.row];
  [cellViewModel setDataModel:item
         withIsEditModeSignal:self.viewModel.isEditModeSignal];
  [Cell setCellViewModel:cellViewModel];

4.Cell's ViewModel's -(void)setDataModel:(DataModel)data withIsEditModeSignal:(RACSignal*)isEditModeSignal

 self.thing1Signal = [[RACSignal combineLatest:@[self.isEditModeSignal,
                                                     other1Signal,
                                                     other2Signal]
                                 reduce:^id(NSNumber *isEditMode,
                                            NSNumber *other1,
                                            NSNumber *other2){
                                     return @(isEditMode.boolValue && other1.boolValue && other2.boolValue);
                                 }];

 self.thing2Signal = [[RACSignal combineLatest:@[self.isEditModeSignal,
                                                     other3Signal,
                                                     other4Signal]
                                 reduce:^id(NSNumber *isEditMode,
                                            NSNumber *other3,
                                            NSNumber *other4){
                                     return @(isEditMode.boolValue && other3.boolValue && other4.boolValue);
                                 }];

5.Cell.m's -(void)setCellViewModel:(CellViewModel*)viewModel

 [[[self.viewModel.thing1Signal deliverOnMainThread] takeUntil:self.rac_prepareForReuseSignal]  subscribeNext:^(NSNumber *isHidden) {
  self.icon1.hidden = isHidden.boolValue;
 }];

 [[[self.viewModel.thing2Signal deliverOnMainThread] takeUntil:self.rac_prepareForReuseSignal]  subscribeNext:^(NSNumber *isHidden) {
  self.icon2.hidden = isHidden.boolValue;
 }];
JerryZhou
  • 4,566
  • 3
  • 37
  • 60

2 Answers2

0

Aha, I found the problem: I use self.isEditModeSignal = RACObserve(self, isEditMode); Which I should use self.isEditModeSignal = RACObserve(self, editMode);. That's the root cause.

JerryZhou
  • 4,566
  • 3
  • 37
  • 60
0

This code is really bad. You're not using ReactiveCocoa the way it is meant to. A better way is to be binding between cellviewmodels and collectionview viewmodels. No need to trigger a refresh at all.

Like so:

// In cell viewmodel's init method:
RAC(self,isEditMode) = RACObserve(self, collectionViewModel.isEditMode); 
//Bind view stuff to: RACObserve(self,isEditMode)

//In collectionview viewmodel init method:
RAC(self,isEditMode) = [[[self.editButton.rac_command executionSignals] flatten] scanWithStart:@NO reduce:id^(NSNumber * running, id next) {
  return @(![running boolValue]);
}];

//In collectionview
RAC(self.editButton.titleLabel, text) = [RACObserve(self.viewModel, isEditMode) map:(NSString *)^(NSNumber * x) {
  [x boolValue] ? @"Edit" : @"Done";
}];

And instead of using combineLatest use the if signal.

Fredrik E
  • 1,840
  • 13
  • 18
  • yes, I don't need to observe editButton's button click event to reload the data. – JerryZhou Oct 21 '15 at 11:22
  • Hi, why do you need flatten here? – JerryZhou Oct 21 '15 at 11:34
  • If I not misunderstood, your code for isEditMode will only be YES when button is clicked down and before things finished. Actually for my requirement, click the button just switch into edit mode and that's it. and edit will happen later. – JerryZhou Oct 21 '15 at 11:41
  • According to http://stackoverflow.com/questions/22366964. `executionSignals] flatten] scanWithStart ` will not fire. – JerryZhou Oct 22 '15 at 06:58