Reputation: 5248
I think I'm having a really weird issue here. In some of my TableViews, when I load images from Parse, the cells that don't have any data sometimes displays other images.
The way I have my code is to check for the existence of the file on Parse, and if there is a picture, the PFImageView
loads the image in the background for each cell.
But, if there is no image stored in the database, the PFImageView
is supposed to use a local image that's a placeholder. However, often in my PFTableView
, the cells without image data take on images from other cells. Does anyone have any idea why? Or know of a fix?
Here's the code:
if business["businessImage"] as? PFFile != nil {
var file: PFFile = business["businessImage"] as PFFile
cell.businessPhoto.file = file
cell.businessPhoto.loadInBackground()
}
else {
cell.businessPhoto.image = UIImage(named: "placeholder user photo")
}
Is it because I'm using loadInBackground()
instead of loadInBackgroundWithBlock()
?
Upvotes: 0
Views: 976
Reputation: 5248
Without using cache, the workaround I found is to first set the image file in cellForRowAtIndexPath
to the placeholder image, and then if the image object was found on the server, the cells image is set to the new file, and then loads it in the background.
Here is the code:
myCell.profilePic.image = UIImage(named: "placeholder user image")
if let file: PFFile = object["profilePicture"] as? PFFile {
myCell.profilePic.file = file
myCell.profilePic.loadInBackground()
}
Thanks everyone for all the help!
Upvotes: 2
Reputation: 62676
The question doesn't show the code where business is set based on the indexPath. Hopefully it's just a simple lookup in an array based on row.
One certain issue with the posted code is that it doesn't immediately set the cell.businessPhoto.image
in the case where you do the asynch fetch.
The effect you'll see is that the cell will contain an image from another row (because of reuse) while the fetch of the correct image is happening. The solution is to set a placeholder image unconditionally.
The second issue is more optional, but almost required: cache images. This way, you don't keep re-fetching as the user scrolls around. That leads to a different organization in your cellForRowAtIndexPath code:
// this outer conditional is your original code
if (this business has a "businessImage" PFFile) {
// new: check for cached image
if (the image is cached) {
set cell image to the cached image
} else {
// new: always set a placeholder, maybe a special one for fetching
set cell image to a placeholder (one that indicates fetching)
asynch fetch the image, with completion block {
cache the image
set cell image to the image
}
}
} else {
set cell image to a placeholder (one that indicates no image)
}
Note that we set the cell image immediately in every case -- even in the case when we're starting a fetch. Done this way, there should be no need to implement the prepareForReuse or didEndDisplay hooks.
Upvotes: 1
Reputation: 2077
When you scroll through tableview, cells are reused. Image that was shown before in that cell is not cleared. You can use either UITableViewCell prepareForReuse method or UITableView delegates didEndDisplayingCell / willDisplayCell to nullify image and cancel loading or that cell.
Update
try this:
func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.businessPhoto.file.cancel()
cell.businessPhoto.image = nil
}
Make sure, that instead of UITableViewCell here you use your custom cell class
Upvotes: 1