Reputation: 2893
I have read a similar post in Reusable cell old image showing and I am still getting the same issues. Essentially I have a TableView that downloads images from amazon s3 as you scroll down everything works good until you get to about the 12th or 13th image. What happens is that the image in the row before shows up in the new row for about 2 seconds while the new image is being downloaded . This is my code ( I'm still new at swift and learning IOS) . The stream_image_string as the full URL to download the images and PicHeight is an integer saved with the image height since every image usually has a different height .
var Stream_Cache = NSCache<AnyObject, AnyObject>()
var stream_image_string = [String]()
var PicHeight = [Int]()
This below is inside the UITableViewCell, first I check if there is a url which it will contain more than 0 characters . I then check if the image/url is saved in the Cache if not then I download it .
if stream_image_string[indexPath.row].characters.count > 0 {
if let image = Stream_Cache.object(forKey: stream_image_string[indexPath.row] as AnyObject) as? UIImage {
DispatchQueue.main.async(execute: { () -> Void in
cell.stream_image.image = image
})
} else {
if cell.stream_image != nil {
let strCellImageURL = self.stream_image_string[indexPath.row]
let imgURL: NSURL = NSURL(string: strCellImageURL)!
let request:NSURLRequest = NSURLRequest(url: imgURL as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
cell.Stream_Image_Height.constant = CGFloat(Float(cell.pic_height!))
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
DispatchQueue.main.async(execute: { () -> Void in
if data != nil {
cell.stream_image.image = UIImage(data: data!)
} else {
cell.Stream_Image_Height.constant = 0
cell.stream_image.image = nil
}
})
});
task.resume()
}
}
} else {
cell.Stream_Image_Height.constant = 0
}
In my UITableViewCell file I set the image to a default image in case it wasn't done loading the new image but it hasn't worked
class HomePageTVC: UITableViewCell {
@IBOutlet weak var stream_image: UIImageView!
var pic_height: Int?
override func awakeFromNib() {
super.awakeFromNib()
stream_image.image = #imageLiteral(resourceName: "defaultImage")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
any suggestions would be great
Upvotes: 4
Views: 1255
Reputation: 131408
You're facing a pretty common cell reuse issue. When you dequeue a cell that was used before, it may already have an image installed in its image view. Set the image to nil before beginning an async download:
if let imageString = stream_image_string[indexPath.row].characters,
!imageString.isEmpty {
if let image = Stream_Cache.object(forKey: imageString) as? UIImage {
cell.stream_image.image = image
} else {
//Clear out any old image left in the recycled image view.
cell.stream_image.image = nil
//Your code to download the image goes here
}
}
Note that there's no need to wrap the cell.stream_image.image = image
code in a call to DispatchQueue.main.async()
. That code will be run on the main thread.
You do, however, need the second DispatchQueue.main.async()
wrapper around the code inside the dataTask's completionHandler, since URLSession
's completion handers are called on a background queue by default.
Upvotes: 4