I am trying to code with ReactiveCocoa and the MVVM pattern and I am trying to setup a custom UITableViewCel
l to update its labels when the according viewModel
is getting a new model object.
The unit tests are passing so I know the view model itself is working so far. But I do not get the UILabel
s to update their attributed text.
Here is my code for the UITableViewCellModel
:
@interface GYMWorkoutTableViewCellModel : NSObject
@property(nonatomic, copy, readonly) NSAttributedString *workoutName;
@property(nonatomic, copy, readonly) NSAttributedString *numberOfExercises;
@property(nonatomic, strong) GYMWorkout *workout;
@end
@implementation GYMWorkoutTableViewCellModel
- (id)init {
self = [super init];
if (!self) return nil;
RACSignal *newWorkoutSignal = [RACObserve(self, workout) ignore:nil];
RAC(self, workoutName) = [newWorkoutSignal map:^id(GYMWorkout *workout1) {
return [[NSAttributedString alloc] initWithString:workout1.name];
}];
RAC(self, numberOfExercises) = [newWorkoutSignal map:^id(GYMWorkout *workout2) {
NSString *numberOfExercisesString = [@([workout2.exercises count]) stringValue];
return [[NSAttributedString alloc] initWithString:numberOfExercisesString];
}];
return self;
}
@end
And here is the code for the cell itself:
@interface GYMWorkoutTableViewCell : UITableViewCell
@property(nonatomic, strong) IBOutlet UILabel *workoutNameLabel;
@property(nonatomic, strong) IBOutlet UILabel *numberOfExercisesLabel;
@property(nonatomic, strong) GYMWorkoutTableViewCellModel *viewModel;
@end
@implementation GYMWorkoutTableViewCell
- (id)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (!self) return nil;
self.viewModel = [GYMWorkoutTableViewCellModel new];
RAC(self.workoutNameLabel, attributedText) = RACObserve(self, viewModel.workoutName);
RAC(self.numberOfExercisesLabel, attributedText) = RACObserve(self, viewModel.numberOfExercises);
return self;
}
@end
I am setting the workout property in the tableView:cellForRowAtIndexPath:
method of the according view controller like this:
GYMWorkoutTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"WorkoutCellIdentifier" forIndexPath:indexPath];
GYMWorkout *workout = [self.viewModel workoutAtIndexPath:indexPath];
cell.viewModel.workout = workout;
return cell;
Can anyone give me hints why the RAC()
bindings in the GymWorkoutTableViewCell
do not update the UILabel
s?
When I change the code in the initWithCoder:
method to
[RACObserve(self, viewModel.workout) subscribeNext:^(GYMWorkout *gymWorkout) {
self.workoutNameLabel.text = gymWorkout.name;
}];
the text of the UILabel
s is changed. But this defeats the need for the model.
Ok - I figured it out. The labels where all nil in initWithCoder: - so I had to postpone the RAC() binding until the everything is loaded from the nib.
- (void)awakeFromNib {
[super awakeFromNib];
RAC(self.workoutNameLabel, text) = RACObserve(self, viewModel.workoutName);
RAC(self.numberOfExercisesLabel, text) = RACObserve(self, viewModel.numberOfExercises);
}
And now the labels get updated :).