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;
}];
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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.