Ios UICollectionViewCell图像在API调用后重新加载问题

Ios UICollectionViewCell图像在API调用后重新加载问题,ios,swift,uitableview,Ios,Swift,Uitableview,我正在尝试加载URL所在的特定单元格的图像。具有下载图像并通过回调方法发送的函数,但回调后,其他单元格也会被下载的图像加载。谢谢你 下面是代码示例。在方法cellForItemAtIndexPath 让stationCollectionViewcell:stationCollectionViewcell=collectionView.DequeueReuseAbleCell(使用ReuseIdentifier:“stationCell”,for:indexPath)作为!StationColle

我正在尝试加载URL所在的特定单元格的图像。具有下载图像并通过回调方法发送的函数,但回调后,其他单元格也会被下载的图像加载。谢谢你

下面是代码示例。在方法
cellForItemAtIndexPath

让stationCollectionViewcell:stationCollectionViewcell=collectionView.DequeueReuseAbleCell(使用ReuseIdentifier:“stationCell”,for:indexPath)作为!StationCollectionViewCell
如果imageURL.contains(“http”){
self.loadImageWithURL(url:url(字符串:station.imageURL)!){(图像)在
stationCollectionViewcell.RadioMgView.image=图像
}
}否则,如果imageURL!="" {
stationCollectionViewcell.RadioMgView.image=UIImage(名为:“station therockfm”)
}否则{
stationCollectionViewcell.RadioMgView.image=UIImage(名为:“stationImage”)
}
以及下载图像的功能

func loadImageWithURL(url:url,回调:@escaping(UIImage)->()){
打印(“这是正在执行的loadImageWithURL”)
让session=URLSession.shared
让downloadTask=session.downloadTask(带url,completionHandler:{
url、响应、中的错误
如果错误==nil&&url!=nil{
如果let data=NSData(contentsOf:url!){
如果let image=UIImage(数据:数据作为数据){
DispatchQueue.main.async(执行:{
回调(图像)
})
}
}
}
})
downloadTask.resume()
}

每次单元都在重复使用,控制器中也有异步调用。在下载完成过程中,需要通过
indepath
重新加载单元格

另外,在
prepareforeuse

 override func prepareForReuse() {
    super.prepareForReuse()

    stationCollectionViewcell.radioImgView.image = nil
}
异步映像的最佳解决方案是使用缓存

let imageCache: NSCache<NSString, UIImage> = NSCache<NSString, UIImage>()
下一次,当单元格出现时,检查图像是否已存在于
imageCache

如果是,请使用缓存中的映像;如果不是,请下载映像 代码应该如下所示:

if imageURL.contains("http") {
        if let image = imageCache.object(forKey: station.imageURL as NSString) {
            stationCollectionViewcell.radioImgView.image = image
        } else {
            self.loadImageWithURL(url: URL(string: station.imageURL)!) { [weak self] (image) in
                self?.imageCache.setObject(image, forKey: url as NSString)
                self?.collectionView.collectionView.reloadItems(at: [indexPath])
            }
        }


    } else if imageURL != "" {
        stationCollectionViewcell.radioImgView.image = UIImage(named: "station-therockfm")

    } else {
        stationCollectionViewcell.radioImgView.image = UIImage(named: "stationImage")

    }

在重新使用单元格之前,您应该重置
图像
,因为在下载新的单元格之前,它会与以前的图像一起重新使用。另外,您应该将保存的url和回调中的url进行比较,因为当单元格被重用时,回调可能会返回

// reset image 
override func prepareForReuse() {
    super.prepareForReuse()

    radioImgView.image = nil // set nil or default image
}
将url添加到回调

func loadImageWithURL(url: URL, callback: @escaping (UIImage, URL) -> ()) {
print("This is getting excuted loadImageWithURL")
let session = URLSession.shared
let downloadTask = session.downloadTask(with: url, completionHandler: {
     url, response, error in

    if error == nil && url != nil {
        if let data = NSData(contentsOf: url!) {
            if let image = UIImage(data: data as Data) {
                DispatchQueue.main.async(execute: {
                    callback(image, url!)
                })
            }
        }
    }
})
     downloadTask.resume()
}
比较url

let stationCollectionViewcell : StationCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "stationCell", for: indexPath) as! StationCollectionViewCell

if imageURL.contains("http") {
   let url = URL(string: station.imageURL)!
   self.loadImageWithURL(url: url) { (image, callbackUrl) in
       guard url == callbackUrl else { return }
       stationCollectionViewcell.radioImgView.image = image
   }
} else if imageURL != "" {
   stationCollectionViewcell.radioImgView.image = UIImage(named: "station-therockfm")
} else {
   stationCollectionViewcell.radioImgView.image = UIImage(named: "stationImage")
}

我希望它会运行良好。

import UIKit    

let imageCache = NSCache<AnyObject, AnyObject>()

class CustomImageView : UIImageView {

    var imgUrlString : String?

    func loadImageWithURL(urlString : String) {

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

        image = nil
        if let imgFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
            self.image = imgFromCache
            return
        }

        URLSession.shared.dataTask(with: url) { (data, resposne, error) in
            if error != nil {
                print(error)
                return
            }

            DispatchQueue.main.sync {
                let imageToCache = UIImage(data: data!)
                imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
                if self.imgUrlString == urlString {
                    self.image = imageToCache
                }

            }

        }.resume()
    }
}

细胞被重复使用。首先将
radiomgview.image
重置为
nil
(或占位符)。@Larme尝试了此操作,但没有成功,请给出一些示例。
import UIKit    

let imageCache = NSCache<AnyObject, AnyObject>()

class CustomImageView : UIImageView {

    var imgUrlString : String?

    func loadImageWithURL(urlString : String) {

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

        image = nil
        if let imgFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
            self.image = imgFromCache
            return
        }

        URLSession.shared.dataTask(with: url) { (data, resposne, error) in
            if error != nil {
                print(error)
                return
            }

            DispatchQueue.main.sync {
                let imageToCache = UIImage(data: data!)
                imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
                if self.imgUrlString == urlString {
                    self.image = imageToCache
                }

            }

        }.resume()
    }
}
let thumbnailImageView : CustomImageView = {
        let imgView = CustomImageView()
        imgView.translatesAutoresizingMaskIntoConstraints = false
        imgView.image = #imageLiteral(resourceName: "taylor_swift_blank_space")
        imgView.contentMode = .scaleAspectFill
        imgView.clipsToBounds = true
        return imgView
    }()