Josh
Josh

Reputation: 2587

UITableView cell is displaying an incorrect image, even while setting the image to nil as the first step in tableView.dequeueReusableCell

I'm trying to do something very basic, but the fix proposed in other similar questions does not seem to be working. I have an image cache, and a tableView. I want to display the image from the cache if it exists, otherwise there should be nothing. For some reason the tableView is still displaying a reused cell with the wrong image, even when I set the image view to nil. Below is my code:

let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath) as! SearchResultsTableViewCell

    cell.profilePhoto?.image = nil
    cell.profilePhoto?.backgroundColor = UIColor.gray
    if let userID = myObject.posterId, let profileImage = self.imageCache.object(forKey: userID as AnyObject) {
        cell.profilePhoto?.image = profileImage
    } else {
        if let userId = myObject.posterId {
            downloadImage.beginImageDownload() {
                (imageOptional) in
                if let image = imageOptional {
                    cell.profilePhoto?.image = image
                    self.imageCache.setObject(image, forKey: userId as AnyObject)
                }
            }
        }
    }

What am I doing wrong? I can't for the life of me figure out why the image is not being set to nil, even though I do that as the first step!

Upvotes: 6

Views: 2027

Answers (2)

Oleh Zayats
Oleh Zayats

Reputation: 2443

The problem is downloadImage.beginImageDownload closures are holding references to the uitableview cells.

When you complete the image download, you set cell.profilePhoto?.image property, even if the tableView recycles reusable cells to display a different row.

Assign your cell's tag to the indexPath.row and test if cell is still relevant for assigning downloaded image:

/* right after cell dequeue */
cell.tag = indexPath.row

then

/* download finished here */
if cell.tag == indexPath.row {
    /* yeah, I want to rock this cell with my downloaded image! */
    cell.profilePhoto?.image = downloadedImage
}

Be aware: this will only work in tableview with one section.

P.S. You can place the clean up of your cells in prepareForReuse method inside the SearchResultsTableViewCell to tidy things a little.

Upvotes: 6

Jonah
Jonah

Reputation: 17958

You appear to be setting your image to nil but have you considered the downloads which might be in flight when you reuse that cell? It looks like you could be updating a cell's image when the download for some previous index path finishes.

Upvotes: 0

Related Questions