iOS table view cell doesn't show expected behaviour

157 views Asked by At

Yesterday I asked a question about a cell not showing correctly a button that depends on a string value. Please take a look at it if you want: Strange behaviour on table view with core data.

User @jrturton pointed out following as part of his answer:

A reused cell will have the subview added every time - so there could be many urgent views on top of each other. The cell should only ever add this once and keep it in a property

I think that this answer marks the correct direction I must follow to solve my issue, but I am not able to implement the answer into my code which is following:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    NSManagedObject *managedObject = [fetchedResultsController   objectAtIndexPath:indexPath];

    NSString *isUrgent = [[managedObject valueForKey:@"urgent"]description];


    [[cell textLabel] setText:[[managedObject valueForKey:@"thingName"] description]];


    //urgent

    if ([isUrgent isEqual:@"Urgent"]){
    UIButton *urgentButton = [[UIButton alloc]initWithFrame:CGRectMake(71, 27, 18, 18)];
    [urgentButton setImage:[UIImage imageNamed:@"urgent-3"]forState:UIControlStateNormal];
    [cell addSubview:urgentButton];
        NSLog(isUrgent);
    }
    //not urgent 
    if ([isUrgent isEqual:@"Not urgent"]){
        UIButton *urgentButton = [[UIButton alloc]initWithFrame:CGRectMake(71, 27, 18, 18)];
        [urgentButton setImage:[UIImage imageNamed:nil]forState:UIControlStateNormal];
        [cell addSubview:urgentButton];
        NSLog(isUrgent);
    }


    [[cell detailTextLabel] setText:@"  "];
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
    cell.textLabel.textColor = [UIColor blueColor];
    cell.textLabel.font = [UIFont fontWithName:@"Noteworthy" size:22.0f];
    cell.detailTextLabel.font = [UIFont fontWithName:@"Noteworthy" size:15.0f];

}

The behaviour of the cell must be following:

1. If isUrgent = @"Urgent", the cell must show urgentButton (including imageNamed:@"urgent-3":
2. Else no button has to be shown.

The current behaviour is as follows:

1. If isUrgent = @"Urgent", the cell shows urgentButton (including imageNamed:@"urgent-3".
2. If isUrgent = @"Not urgent", value tested in NSLog, the cell shows urgentButton too.

This behavior only happens when the cell has changed its isUrgent value at least one time.

I need your help to implement the above mentioned answer. Thank you.

2

There are 2 answers

1
danh On BEST ANSWER

I agree with @wuii, but I think the answer can be clearer. The idea is that reused cells have their view hierarchy already built, so it's harmful to do it again each time a cell is reused (which is all of the time during scrolling). The advice can be encapsulated in a "lazy getter" that returns the cell's urgent button.

// above @implementation
#define kURGENT_BUTTON_TAG  (256)

- (UIButton *)urgentButtonInCell:(UITableViewCell *)cell {

    UIButton *urgentButton = (UIButton *)[cell viewWithTag:kURGENT_BUTTON_TAG];
    if (!urgentButton) {
        urgentButton = [[UIButton alloc]initWithFrame:CGRectMake(71, 27, 18, 18)];
        urgentButton.tag = kURGENT_BUTTON_TAG;
        [cell addSubview:urgentButton];
    }
    return urgentButton;
}

Now your configureCell can just ask for the button:

UIButton *urgentButton = [self urgentButtonInCell:cell];
UIImage *image = ([isUrgent isEqualToString:@"Urgent"])? [UIImage imageNamed:@"urgent-3"] : nil;
[urgentButton setImage:image forState:UIControlStateNormal];
1
Aditya Deshmane On

You will need to keep track of your cell is reused or it's fresh one.

What here might be happening is you are adding UIButton to reused cell, but it already has button having "urgent-3" image set

Do this

  1. Pass one more BOOL parameter to configure cell isFreshCell with value set as per new cell or not.

**

MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
isFreshCell = NO;
if(cell==nil)
{
 isFreshCell = YES;
 cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
} 
[self configureCell:cell atIndexPath:indexPath isFreshCell:isFreshCell];

New method signature

-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath isFreshCell:(BOOL) isFreshCell

2 When you add button set some tag to it.

3 If isFreshCell is false dont add new button as it is already there and you can access this button using subviewWithTag method like this cell.contentView.subviewWithTag and then set image or set nil image or just hide button