我是在Swift中解析json的新手,在我的应用程序中我创建了一个收件箱。在此收件箱中,我在每个单元格中加载配置文件图像和名称。我在网上找到了一个带有视频游戏角色及其图像的API供测试。但是,当解析json并将其放入单元格时,应用程序会加载单元格,有时图像会移动到其他单元格或复制。我以前见过这个,但过去的答案都没有解决我的解决方案。
这是加载时看起来不正确的样子
以下是一秒后发生的事情仍然不正确,您可以看到重复
这是我的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
}
答案 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() }
}
}
}