在滚动之前,TableView图像不会加载

时间:2016-12-19 14:02:52

标签: ios swift cocoa-touch firebase tableview

我正在使用Firebase将我的图片加载到我的手机ImageView中,但是!这儿存在一个问题。我在reusable cells加载时使用缓存机制阻止图片重新下载,但在我滚动TableView之前图片无法加载。

这是代码;

     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
    cell.imgv.image = nil

if let urlString =  self.filteredFlats[indexPath.row].flatThumbnailImage?.imageDownloadURL
    {
        imageURLString = urlString

        let url = URL(string: urlString)
        if let imagefromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage
        {
            DispatchQueue.main.async {
                cell.imgv.image = imagefromCache
                return
            }
        }
        else
        {

            URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
                DispatchQueue.main.async {

                    let imagetoCache = UIImage(data:data!)

                    if self.imageURLString == urlString
                    {
                        cell.imgv.image = imagetoCache

                    }
                    self.imageCache.setObject(imagetoCache!, forKey: urlString as AnyObject)

                }
            }).resume()
        }
    }
    return cell
}

我认为问题在于,当URLSession下载图片并将其设置为ImageView时,加载的图片在向上和向下滚动时调用indexpath.row时才会显示

我意识到它的原因就是这个if语句;

 if self.imageURLString == urlString

但是,如果我删除它,细胞会变得更糟,因为可重复使用的细胞的行为。有些单元格仍然显示旧的缓存图像。

真的不知道发生了什么。没想到TableViews是一种复杂的结构。

感谢。

3 个答案:

答案 0 :(得分:0)

我猜测imageURLString是你的类的一个字段(也许是UIViewController)。 这意味着每次进入方法时imageURLString = urlString都会更改其值。

当表格呈现时,它将为每个单元格调用方法,如果所需图像不在缓存中,则每次触发下载。但是在这些调用之后,imageURLString的值将是用于最后一个单元格的URL,因此只有这个单元格才会实际使用已加载的图像。

如果要修复代码,每个单元格应该有一个imageURLString,例如将字段移动到单元格类(在这种情况下创建UITableViewCell子类),并替换{ {1}}和imageURLString self.imageURLString

答案 1 :(得分:0)

我相信imageCache必须是全局的,不应该放在tableView(_:cellForRowAt :)中。

相反,除了var imageCache = String:UIImage之外,将所有内容都放在Custom UIImageView Class中。把它留给全球。

将所有将使用此CustomImageView类中的loadImage(urlString:String)函数的UIImageView更改为CustomImageView!。

示例:

@IBOutlet weak var userImage:UIImageView!

更改为

@IBOutlet weak var userImage:CustomImageView!

import UIKit

// global var
var imageCache = [String: UIImage]()

class CustomImageView: UIImageView {

    var lastURLUsedToLoadImage: String?

    func loadImage(urlString: String) {
        lastURLUsedToLoadImage = urlString

        self.image = nil

        if let cachedImage = imageCache[urlString] {
            self.image = cachedImage
            return
        }

        guard let url = URL(string: urlString) else { return }

        URLSession.shared.dataTask(with: url) { (data, response, err) in
            if let err = err {
                print("Failed to fetch post image:", err)
                return
            }

            if url.absoluteString != self.lastURLUsedToLoadImage {
                return
            }

            guard let imageData = data else { return }

            let photoImage = UIImage(data: imageData)

            imageCache[url.absoluteString] = photoImage

            // update the UI
            DispatchQueue.main.async {
                self.image = photoImage
            }

            }.resume()
    }
}

调用load方法的示例:

cell.userImage.loadImage(urlString: userImageUrl)

答案 2 :(得分:0)

我使用从YouTube上的iOS教程中学习的以下方法解决它。 我们可以创建一个CustomImageView类,let imageCache = NSCache<AnyObject, AnyObject>()来保存图像Cache。当滚动tableview时,如果imageView有一个imageCache,我们直接使用它。但是如果它不存在,我们将下载带有图片URL字符串的图片并保存。

import UIKit

let imageCache = NSCache<AnyObject, AnyObject>()

class  CustomImageView: UIImageView {

    var imageUrlString :String?

    func loadImageWithString(_ urlString:String){

        imageUrlString = urlString

        let request = URLRequest(url: URL(string:urlString)!)

        self.image = nil

        //imageCache exist,and use it directly
        if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {

            self.image = imageFromCache
        }

        //imageCache doesn't exist,then download the image and save it
        URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in

            guard let data = data, error == nil else {
                print(error?.localizedDescription as Any)
                return
            }

            DispatchQueue.main.async() { 

                let imageToCache = UIImage(data: data)

                imageCache.setObject(imageToCache!, forKey: urlString as String as AnyObject )

                if self.imageUrlString == urlString{

                    self.image = imageToCache
                }
            }

        }).resume()

    }

}

在自定义单元格类文件中,我们可以按如下方式使用它:

 if let imageUrlString = thumbnailUrlString {
               thumbnailImageView.loadImageWithString(imageUrlString)
            }

注意1,thumbnailImageView:CustomImageView 2,thumbnailUrlString是可选的