1

I have a custom cell with 3 labels and one button. Everything worked well until I didn't implement tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method for my table view. (I need it because I set the cell height here based on the length of the labels.) The problem is when I tap likeButton the likeCountLabel.text will display the labels sample value from the IB for a sec and then shows the previous (correct) string again in every cell, not just in the tapped. When I remove heightForRowAtIndexPath: it's perfect again. As I discovered it happens after I reload the table view, but don't have any idea, because these labels work perfectly when I don't adjust the height.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {

    static NSString *CellIdentifier = @"cell";
    NewsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    PFQuery *query = [like query];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

        if (objects) {

            NSString *likeNumber = [NSString stringWithFormat:@"%d", objects.count];
            cell.likeCountLabel.text = likeNumber;

        }
    }];

    cell.likeButton.tag = indexPath.row;
    [cell.likeButton addTarget:self action:@selector(didTapLikeButton:) forControlEvents:UIControlEventTouchUpInside];


    cell.usrName.text = object[@"usrName"];
    cell.usrDescription.text = object[@"desc"];
    cell.date.text = object[@"date"];

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {


    static NSString *CellIdentifier = @"cell";
    NewsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    PFObject *object = [self.objects objectAtIndex:indexPath.row];

    cell.usrName.text = object[@"usrName"];
    cell.usrDescription.text = object[@"desc"];
    cell.date.text = object[@"date"];

    //get the height the cell
    //  [cell layoutIfNeeded];
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    //paddign of 1 Point
    return height + 12;
}

- (void)didTapLikeButton:(id)sender {

    // Cast Sender to UIButton
    UIButton *button = (UIButton *)sender;

    PFObject *likeRow = [self.objects objectAtIndex:button.tag];
              [SaveHelper likeObject:likeRow withUploader:[PFUser currentUser]];
    [self.tableView reloadData];


}
gatto
  • 193
  • 1
  • 9

1 Answers1

1

You shouldn't dequeue or instantiate cells in heightForRowAtIndexPath: - this breaks up the pattern (ie: tableView asks for needed height of cell at certain indexPath and you on the other hand ask it to instantiate a cell for the very same indexPath so you could answer about needed height...)

In cellForRowAtIndexPath: a cell is generated (or reused) and filled with data according to the data model. If a cells height depends on the data - this height should be calculated from the data model, too.

To avoid instantiating cells in heightForRowAtIndexPath: you could write up a class method like + (CGFloat) heightOfCellWithContent... and use this method to calculate needed height of certain type of cell within the heightForRowAtIndexPath:.

In other words: you need NewsTableViewCell class to be able to tell you what height would its instance (a cell of that type) need with certain content...

EDIT:

You obviously have a UITableViewCell subclass named NewsTableViewCell and instances of this class expect to be filled with data like usrName, usrDescription...

Add a class method to NewsTableViewCell:

+ (CGFloat)cellHeightNeededForUsrName:(NSString *)usrName
                       usrDescription:(NSString *)usrDescription {
  // calculate the height here
}

or even better in your case:

+ (CGFloat)cellHeightNeededForData:(PFObject *)data {
  // calculate the height here
}

And then modify your - (CGFloat)tableView:heightForRowAtIndexPath: in this manner:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    PFObject *object = [self.objects objectAtIndex:indexPath.row];

    return [NewsTableViewCell cellHeightNeededForData:object];
}
Community
  • 1
  • 1
Rok Jarc
  • 18,235
  • 9
  • 64
  • 120
  • Could you give a little more guidance, should I use the custom cell in the class method? Or what should I use from my existing code in the method? – gatto Mar 08 '15 at 23:40
  • Thanks! I just tried to create an ivar for the cell and use it like self.cell in `heightForRowAtIndexPath:` but doesn't helped. – gatto Mar 08 '15 at 23:47
  • Hope this helps: if not i'll return to your question tomorrow (it's kind of late here...) – Rok Jarc Mar 08 '15 at 23:58
  • Cool, thanks. I would really appreciate it. I've tried what you recommended, but couldn't reproduce this value `CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;` inside the class method so I couldn't run it. I understand the concept, but don't know how could calculate the size properly. – gatto Mar 09 '15 at 00:20
  • I missed the part that you are using autolayout: this makes it a bit more complicated - but still managable. [This thread](http://stackoverflow.com/a/28514006) should help you getting things in order. – Rok Jarc Mar 09 '15 at 09:38