Pregunta

I am trying to code with ReactiveCocoa and the MVVM pattern and I am trying to setup a custom UITableViewCell 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 UILabels 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 UILabels?

Edit

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 UILabels is changed. But this defeats the need for the model.

¿Fue útil?

Solución

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 :).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top