Search code examples
iosreuseidentifier

iOS table view cell doesn't show expected behaviour


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.


Solution

  • 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];