重新加载具有图像的UICollectionViewCell

我正在尝试创build类似Facebook NewsFeed的东西,我正在使用自定义的UICollectionViewCell来显示来自JSON的数据(文本/图像)。 我有2个不同的API。 一个用于文本,另一个用于图像(每个单元格都没有图像)。

所以,首先,我从textAPI中获取所有文本值,并重新加载myCollectionView。 这是完美的。

现在的图像,我使用ImageFetcher来获取图像,

func ImageFetcher(postId : NSNumber, completion : ((_ image: UIImage?) -> Void)!) { var image = UIImage() let urlString = "http://myImageAPI/Image/\(postId)" let jsonUrlString = URL(string: urlString) print(urlString) URLSession.shared.dataTask(with: jsonUrlString!) { (data, response, error) in do { if let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String:Any] { if let images = jsonData["Image"] as? String { if images == "" { print("No Image") } else { let dataDecoded : Data? = Data(base64Encoded: images, options: .ignoreUnknownCharacters) image = UIImage(data: dataDecoded!)! completion(image) } } } else { completion(nil) } } catch { print(error.localizedDescription) } }.resume() } 

要将图像显示在单元格中,

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // Displaying other elements with text DispatchQueue.main.async { self.ImageFetcher(postId: self.myArray[indexPath.item].id!, completion: { (image) -> Void in customCell.mainImage.image = image }) // Declared "indexPaths" var indexPaths = [IndexPath]() // Added this lines // let indexPath = IndexPath(item: indexPath.item, section: 0) // self.indexPaths.append(indexPath) } return customCell } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.jsonParsing() } func jsonParsing() { //Fetching text data from textAPI //DispatchQueue.main.async { // self.collectionView.reloadItems(at: self.indexPaths) //} } 

代码工作没有任何错误,但问题是图片只出现时,我点击它们。 (我可以在单元格中看到空的/白色的imageView,直到我点击它。只要我点击imageView图像出现),我感觉它与DispatchQueue.main.async的东西,但不知道。

获取图像后,我不想重新加载整个collectionView。 只是想重新加载那些有图像的单元格。 我在许多解决scheme中发现了collectionView.reloadItemsAtIndexPaths(myArrayOfIndexPaths) ,但不知道如何使它在这种情况下工作。 任何人都可以帮我吗? 任何帮助都感激不尽。

你能试试吗?

 DispatchQueue.main.async { customCell.mainImage.image = image } 

代替

 customCell.mainImage.image = image 

=====================更新======================

我最终帮助Snehal不仅仅是图像加载问题,还有一些其他的问题与集合视图和图像caching。 我build议他使用像SDWebImage这样的第三方库,但发现他的api在响应中返回的图像是base64string。 所以我只是继续清理他的代码,并写下代码,我认为这可以帮助他。

 import UIKit class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { let imageView = UIImageView() lazy var collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.minimumInteritemSpacing = 10 layout.minimumLineSpacing = 10 layout.scrollDirection = .vertical let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.delegate = self collectionView.dataSource = self collectionView.register(CustomCell.self, forCellWithReuseIdentifier: NSStringFromClass(CustomCell.self)) collectionView.backgroundColor = .clear return collectionView }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(collectionView) } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() collectionView.frame = view.bounds } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 50 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(CustomCell.self), for: indexPath) as! CustomCell cell.imageUrl = "http://myImageAPI/Image/\(postId)" return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.frame.size.width - 2 * 20, height: 100) } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { } } class CustomCell: UICollectionViewCell { let imageView = UIImageView() var imageUrl: String? { didSet { if let imageUrl = imageUrl, let url = URL(string: imageUrl) { dataTask = imageView.loadImage(url: url) } } } var dataTask: URLSessionDataTask? override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .white imageView.backgroundColor = UIColor.lightGray imageView.contentMode = .scaleAspectFit contentView.addSubview(imageView) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func prepareForReuse() { super.prepareForReuse() dataTask?.cancel() imageView.image = nil } override func layoutSubviews() { super.layoutSubviews() imageView.frame = bounds } } extension UIImageView { @discardableResult func loadImage(url: URL) -> URLSessionDataTask? { if let image = ImageLoadManager.manager.cachedImages[url.absoluteString] { self.image = image return nil } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in do { guard let data = data else { return } if let jsonData = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any] { if let images = jsonData["PostImage"] as? String {// Pase the Base64 image string if images == "" { print("No Image") } else { if let dataDecoded = Data(base64Encoded: images, options: .ignoreUnknownCharacters), let decodedImage = UIImage(data: dataDecoded) { DispatchQueue.main.async { ImageLoadManager.manager.cachedImages[url.absoluteString] = decodedImage self.image = decodedImage } } } } } else { DispatchQueue.main.async { self.image = nil } } } catch { print(error.localizedDescription) } } task.resume() return task } } class ImageLoadManager { static let manager = ImageLoadManager() var cachedImages = [String: UIImage]() } 

更好的方法来做到这一点就像创build一个模型,该类包含图像的URL和您的文本variables,如类AnyName {var url:String? var desc:String?

 init(urlValue: String?, descValue:String? ){ url = urlValue desc = descValue } } 

现在在您的viewcontroller上面的类名var array = AnyName的数组现在通过第一个API打你可以设置这个数组中的文本的值,并传递给collectionview和文本加载单元格,此后,您可以更改url的数组值并轻松地重新加载collectionview