1

I have a table view cell with two image views, one image view is a placeholder, and on top of the other image is the actual image I load from the documents directory. I am having issues with the image being incorrectly displayed when the table view resuses the cell.

I solved my problem by using the below method in the cell class, but I have read that this can cause performance issues, any ideas on a better solution?

- (void)prepareForReuse
{
    [[self imageView] setImage:nil];
}
Vikings
  • 2,527
  • 32
  • 45

2 Answers2

2

First of all, you are not calling [super prepareForReuse] like you should.

And the documentation is pretty clear, you should be setting the image in tableView:cellForRowAtIndexPath: because it's content.
If you set the image in tableView:cellForRowAtIndexPath: there is no point to set it to nil in prepareForReuse.

Imagine the following flow.

  1. You scroll down, cell 0 is put onto the queue.
  2. prepareForReuse sets imageView.image to nil
  3. tableView:cellForRowAtIndexPath: dequeues the cell and sets imageView.image to image1

You are setting imageView.image twice.

If you use nil there might be no measurable performance impact at all. But you might come to the idea to actually set a placeHolder image. So the cell is queued and prepared for reuse, you set the placeholder image; later the cell is dequeued and the placeholder image is replaced by a real image before the placeholder image was even visible.

I would remove the prepareForReuse method completely. You don't need it if you set the image in tableView:cellForRowAtIndexPath:


from the documentation:

If a UITableViewCell object is reusable—that is, it has a reuse identifier—this method is invoked just before the object is returned from the UITableView method dequeueReusableCellWithIdentifier:. For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state. The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell. If the cell object does not have an associated reuse identifier, this method is not called. If you override this method, you must be sure to invoke the superclass implementation.

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
  • _"..you should only reset attributes of the cell that are not related to content..."_ - what does _the content_ mean? Should I change cell's label text in `prepareForReuse` or in `tableView:cellForRowAtIndexPath:`? And where should I set, for example, the `hidden` property for some of cell's views? – Artem M Dec 17 '15 at 07:58
0

Since you have a placeholder image behind this image view, There is nothing wrong if you set the top imageview's image to nil.

To enhance the image generating process, you can use a NSCache object like this,

1)

@property(nonatomic, strong) NSCache *imageCache;


2) Call this methods inside tableView cellForRowAtIndexPath: method, the image generating process can be moved into this,

-(UIImage *) imageForIndexPathRow:(int) row{

    id image = [self.imageCache objectForKey:[NSNumber numberWithInt:row]];

    if(!image){//if the image is not in the cache,

        UIImage *newImage; //create image here

        [self.imageCache setObject:newImage forKey:[NSNumber numberWithInt:row]];

        return newImage;
    }

    return (UIImage *) image;
}
Thilina Chamath Hewagama
  • 9,039
  • 3
  • 32
  • 45
  • I'm already using NSCache, just wanted to make sure I was not doing something that will cause performance issues – Vikings May 11 '13 at 16:21