UICollectionview在错误的位置更新随机图像

时间:2018-04-19 15:15:35

标签: ios json swift parsing uicollectionview

我是在Swift中解析json的新手,在我的应用程序中我创建了一个收件箱。在此收件箱中,我在每个单元格中加载配置文件图像和名称。我在网上找到了一个带有视频游戏角色及其图像的API供测试。但是,当解析json并将其放入单元格时,应用程序会加载单元格,有时图像会移动到其他单元格或复制。我以前见过这个,但过去的答案都没有解决我的解决方案。

这是加载时看起来不正确的样子

Here is what it looked like when it loaded which is incorrect

以下是一秒后发生的事情仍然不正确,您可以看到重复

Here is what happened one second later which is still incorrect and you can see duplication

这是我的CollectionViewCell.Swift文件

class CollectionViewCell: UICollectionViewCell {

@IBOutlet weak var imageCell: UIImageView!
@IBOutlet weak var dateCell: UILabel!

override func prepareForReuse() {
    self.imageCell.image = nil
    self.imageCell.setNeedsDisplay() // tried adding after some     recommendations
    self.setNeedsDisplay()         // tried adding after some recommendations
    super.prepareForReuse()

    }

}

这是我在网上找到的图片的主要收件箱视图控制器扩展程序

extension UIImageView {
func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
    contentMode = mode
    URLSession.shared.dataTask(with: url) { data, response, error 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()
}
func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
    guard let url = URL(string: link) else { return }
    downloadedFrom(url: url, contentMode: mode)

    }
}

这是收件箱视图控制器代码的其余部分(为此问题而从中删除了不相关的代码)

class InboxViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {


@IBOutlet weak var inboxCollection: UICollectionView!


struct Hero: Decodable {
    let localized_name: String
    let img: String
}

var heroes = [Hero]()


override func viewDidLoad() {
    super.viewDidLoad()

    inboxCollection.dataSource = self

    let url = URL(string: "https://api.opendota.com/api/heroStats")
    URLSession.shared.dataTask(with: url!) { (data, response, error) in

        if error == nil {

            do {
                self.heroes = try JSONDecoder().decode([Hero].self, from: data!)
            }catch {
                print("Parse Error")
            }

            DispatchQueue.main.async {
                self.inboxCollection.reloadData()
            }
        }

    }.resume()



}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.heroes.count
}


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
    cell.dateCell.text = heroes[indexPath.row].localized_name.capitalized
    let defaultLink = "https://api.opendota.com"
    cell.imageCell.image = nil
    let completelink = defaultLink + heroes[indexPath.row].img
    cell.imageCell.image = nil
    cell.imageCell.downloadedFrom(link: completelink)
    cell.imageCell.clipsToBounds = true
    cell.imageCell.layer.cornerRadius = cell.imageCell.frame.height / 2
    cell.imageCell.contentMode = .scaleAspectFill
    cell.imageCell.image = nil

    return cell

}

1 个答案:

答案 0 :(得分:0)

您不应该在UIImageView中设置UIImageView的图像。事实上,甚至不创建两个单独的方法 - 你没有充分的理由。下载UIViewController中的每个图像,并使用字典将英雄的名字映射到他们的图像,如下所示:

var heroImages = [String:URL]()
    func getDataFromUrl(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            completion(data, response, error)
        }.resume()
    }

func getImages() {
    for hero in self.heroes {
        let url = NSURL(string: hero)
        getDataFromURL(url: url, completion: {(data: Data?, response:URLResponse?, error: Error?) in 
        if (data != nil) { 
            image = UIImage(data: data)
            heroImages[hero] = image }
            if (heroImages.count == self.heroes.count) {
                 // We've downloaded all the images, update collection view
                 DispatchQueue.main.async { self.collectionView.reloadData() }
}
}
}