json - 无法在 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()
}
解决方案
通过像这样加载图像,您将遇到图像被加载到错误单元格中的问题,原因是:
- 加载它们所需的时间,
- 你的图片没有被缓存,
- 当您滚动时,您的单元格会出列,但相关的加载任务不会被取消。
如果您在 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 。
推荐阅读
- vb.net - 当用户没有在多行文本框的第二行输入文本时,如何添加错误消息?
- sql - 我不知道 SELECT for NAME, SURNAME, AGE, OS_NAME where age> = 15 之后会发生什么
- kernel - media-ctl IPU 绑定:无法设置链接
- momentjs - 如何使用时刻从两个日期范围获得星期五到星期五的星期
- c# - WindowStartupLocation CenterOwner is only working in Visual Studio
- rxjs - BehaviorSubject 触发两次
- javascript - 调用数组时出错:给定的每一行必须为空或数组
- hyperledger-fabric - Hyperledger Fabric 智能合约中的读写操作
- python - 我应该如何使用 python Selenium 进行正确的循环功能?
- python - 我如何将自己连接为其他用户?