Matteo Serpentoni
Matteo Serpentoni

Reputation: 573

Async image loading from url inside a UITableView cell - wrong image loading while scrolling

I have a tableView that displays an image in the cell. Most of the time the correct image will be displayed, however occasionally it will display the wrong image (usually if scrolling down the tableView very quickly). I download the images asynchronously.

cell.profImg.getImgFromUrl(link: man.img, contentMode: cell.profImg.contentMode)

And here i do async request:

extension UIImageView {
func getImgFromUrl(link link:String, contentMode mode: UIViewContentMode) {
    guard
        let url = NSURL(string: link)
        else {return}
    contentMode = mode
    NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
        guard
            let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
            let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
            let data = data where error == nil,
            let image = UIImage(data: data)
            else { return }
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            self.image = image
        }
    }).resume()
    }
}

Upvotes: 3

Views: 2046

Answers (1)

Julien Quere
Julien Quere

Reputation: 2459

I think it's because you do not reset the content of your UIImageView when you start loading you HTTP image. So, when the cell is reused, you display the previously loaded image.

You just have to start your getImgFromUrl by something like self.image = nil (if you want a blank image) or self.image = myPlaceholderImage (if you want a placeholder image during the loading time). Here is how to integrate it in your code:

extension UIImageView {
    
    func getImgFromUrl(link: String, contentMode mode: UIView.ContentMode) {
        guard let url = URL(string: link)  else { return }
        contentMode = mode
        URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil, let image = UIImage(data: data) else { return }
            DispatchQueue.main.async {
                self.image = image
            }
        }).resume()
    }
}

But I think you should consider the use of SDWebImage. This library provides a category for UIImageView with support for remote images coming from the web. It will be much more efficient and easier for you.

Upvotes: 1

Related Questions