Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImageViews in UITableViewCells are recreating themselves in cached cells

I've got a UITableViewCell and I need to randomly put interstitial images into some of them. This is working, but due to the caching of the cells, the images are repeating themselves further down the table. Let's say I've pre-decided to put images in cells 1, 12, and 25, those cells will have their images, but after cell 1, cells 4, 8, etc. might also contain that first image.

I'm guessing what I need to do is specifically tell cellForRowAtIndexPath clear the cache and remove any images if it doesn't meet the criteria to add an image. How would I go about doing that? I've already tried an else on the if statement that makes the decision and assigns the image. In that else, I've tried setting the UIImageView's image to nil, but that hasn't made any difference.

Is there any other way I can clear the cache to prevent these images from spamming their way down the page at regular intervals? Here's my cellForRowAtIndexPath method, and the lines currently in that last else aren't having an effect on the images, so they'll (I think) need replacing with something that works!

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    // Make and allocate the cell if necessary.
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier: @"Cell"];
    if (cell == nil) {
        cell = [[CustomCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: @"Cell"];
    }
    cell.lineLabel.text = [[self.fetchedResultsController objectAtIndexPath: indexPath] line];
    cell.actorLabel.text = [[self.fetchedResultsController objectAtIndexPath: indexPath] actor];
    [cell.lineLabel sizeToFitMultipleLines];

    // Get the size each label needs to be when constrained to set width and very long height (8000).
    CGSize labelSize = [cell.lineLabel.text sizeWithFont: cell.lineLabel.font constrainedToSize: CGSizeMake(265, 8000)];

    if ([[cellsToContainInterstitialImages allKeys] containsObject: [thisLine.lineID stringValue]]) {

        UIImageView *interstitialImage = [[UIImageView alloc] init];
        NSNumber *cellTypeNumber = [cellsToContainInterstitialImages valueForKey: [thisLine.lineID stringValue]];
        kInterstitialCellType cellType = [cellTypeNumber intValue];

        if (cellType == kInterstitialCellTypeFirst) {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"man.png"]];
        }
        else if (cellType == kInterstitialCellTypeSecond) {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"woman.png"]];
        }
        else {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"child.png"]];
        }

        [interstitialImage setFrame: CGRectMake(10, cell.lineLabel.frame.size.height + cell.actorLabel.frame.size.height + 10, 150, 150)];
        [cell addSubview: interstitialImage];
    } else {
        UIImageView *interstitialImage = [[UIImageView alloc] init];
        [interstitialImage setImage: nil];
    }

    return cell;
}
like image 280
Luke Avatar asked Dec 14 '25 15:12

Luke


1 Answers

The else branch of your code does not add the interstitialImage image to the cell. You should change your code to add the UIImageView in the constructor of the cell, so that in the cellForRowAtIndexPath you'd have to set the image, rather than adding subviews.

Add the UIImageView to your CustomCell, make it private, and provide a property for the cellForRowAtIndexPath to use:

@interface CustomCell : UITableViewCell {
    UIImageView *_interstitialImage;
}
@property (nonatomic,readonly) UIImageView *interstitialImage;
@end

@implementation CustomCell 
-(id)initWithStyle:(UITableViewCellStyle) style reuseIdentifier:(NSString*)reuseId {
    if (self = [super initWithStyle:style reuseIdentifier:reuseId]) {
        _interstitialImage = [[UIImageView alloc] init];
         [_interstitialImage setImage: nil];
         [_interstitialImage setFrame: CGRectMake(10, cell.lineLabel.frame.size.height + cell.actorLabel.frame.size.height + 10, 150, 150)];
         [cell addSubview: _interstitialImage];
    }
    return self;
}
-(UIImageView*)interstitialImage {
    return _interstitialImage;
}
@end

Now your cellForRowAtIndexPath would use cell.interstitialImage instead of allocating the new UIImageView all the time. This would avoid adding the image multiple times:

if ([[cellsToContainInterstitialImages allKeys] containsObject: [thisLine.lineID stringValue]]) {
    NSNumber *cellTypeNumber = [cellsToContainInterstitialImages valueForKey: [thisLine.lineID stringValue]];
    kInterstitialCellType cellType = [cellTypeNumber intValue];

    if (cellType == kInterstitialCellTypeFirst) {
        [cell.interstitialImage setImage:[UIImage imageNamed: @"man.png"]];
    } else if (cellType == kInterstitialCellTypeSecond) {
        [cell.interstitialImage setImage:[UIImage imageNamed: @"woman.png"]];
    } else {
        [cell.interstitialImage setImage: [UIImage imageNamed: @"child.png"]];
    }
} else {
    [cell.interstitialImage setImage: nil];
}
like image 88
Sergey Kalinichenko Avatar answered Dec 18 '25 04:12

Sergey Kalinichenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!