首页 > 解决方案 > 无法在 tableView 单元格中正确设置 JSON 中的图像

问题描述

我必须获得 crytocurrencies 徽标并将它们设置在 tableView 单元格中。JSON具有以下结构

"data": {
        "1": {
            "id": 1,
            "name": "Bitcoin",
            "symbol": "BTC",
            "logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/1.png",
            },
        "2": {
            "id": 2,
            "name": "Litecoin",
            "symbol": "LTC",
            "logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/2.png"
        ...}

这是我的模型:

struct Data: Decodable {
      let data: [String: Id]
}

struct Id: Decodable {
     let logo: String
}

根据文档,我可以通过在此 URL 中添加 id 来获取加密货币的徽标:https ://pro-api.coinmarketcap.com/v1/cryptocurrency/info?id=1,2,3,4,5 ..。因为我需要前 100 种货币,所以我以这种方式获取它们,然后通过 Notification 发送给 TableViewController。

class NetworkManager {
    
    func loadData() {
        
        let ids = (1...100).map { String($0) }.joined(separator: ",")
        
        guard let baseURL = URL(string: "https://pro-api.coinmarketcap.com/v1/cryptocurrency/info?id=\(ids)") else {
            print("Wrong URL")
            return
        }
     
        let finalURL = baseURL
        var request = URLRequest(url: finalURL)
        request.addValue("MyApiKey", forHTTPHeaderField: "X-CMC_PRO_API_KEY")

        let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
            
            if let jsonData = data {
                
                do {
                  let cryptoLogo = try JSONDecoder().decode(Data.self, from: jsonData)
                  NotificationCenter.default.post(name: .getLogos, object: cryptoLogo)
                }
                catch {
                  print(error)
                }
            }
        }
        dataTask.resume()
    }
}

要显示徽标,我正在使用 ImageView 扩展:

extension UIImageView {
    
    func imageFromUrl(urlString: String) {
        if let url = URL(string: urlString) {
            let task = URLSession.shared.dataTask(with: url) { data, response, error in
                guard let data = data, error == nil else { return }
                DispatchQueue.main.async() {
                    self.image = UIImage(data: data)
                }
            }
            task.resume()
        }
    }
}

问题是我可以打印徽标 URL,但无法在 tableView 单元格中正确设置它们。你能说我做错了什么吗?让我担心的是,我在 Postman 中获得的徽标不是按升序排列的。如何对字符串徽标数组进行排序?

@objc func getLogo(notification: Notification) {
    
    if let responce = notification.object as? Data {
        
        for value in responce.data.values {
            data.append(value)
        }
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let crypto = data[indexPath.row]
    if let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath) as? TableViewCell {
        cell.imageCell.imageFromUrl(urlString: crypto.logo)
        return cell
    }
    return UITableViewCell()
}

标签: jsonswift

解决方案


通过像这样加载图像,您将遇到图像被加载到错误单元格中的问题,原因是:

  • 加载它们所需的时间,
  • 你的图片没有被缓存,
  • 当您滚动时,您的单元格会出列,但相关的加载任务不会被取消。

如果您在 TableView 中动态加载图像,我强烈建议您使用 KingFisher 之类的库来轻松加载和缓存您的图像,并在单元格出列时取消请求。

导入 KingFisher 后,您可以像这样创建扩展:

public extension UIImageView {
    func loadKingfisherImage(url: String) {
        self.kf.cancelDownloadTask()
        self.kf.indicatorType = .activity
        self.kf.setImage(with: ImageResource(downloadURL: URL(string: url)!, cacheKey: url)) { result in
            switch result {
                case .success(let value):
                    print("Task done for: \(value.source.url?.absoluteString ?? "")")
                case .failure(let error):
                    print("Failed to load image: \(error.localizedDescription)")
            }
        }
    }
}

用法 :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let crypto = data[indexPath.row]
    if let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath) as? TableViewCell {
        cell.imageCell.loadKingfisherImage(url: crypto.logo)
        return cell
    }
    return UITableViewCell()
}

如果您需要更多功能,请参阅https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet 。


推荐阅读