如何使用JSON解码字典值内的自定义类型?

问题描述

我的JSON:
https://www.cbr-xml-daily.ru/daily_json.js
我的代码

struct CoinData: Decodable {
    let Valute: [String: CoinInfo]
}

struct CoinInfo: Decodable {
    let Name: String
    let Value: Double
}
if let safeData = data {
    if let coinData = self.parseJSON(safeData) {
    print(coinData) 
    }
}
func parseJSON(_ data: Data) -> [String: CoinInfo]? {

    let decoder = JSONDecoder()
     do {
        let decodedData = try decoder.decode(CoinData.self,from: data)
        return decodedData.Valute

     } catch {
        delegate?.didFailWithError(error: error)
        return nil
    }
}

在调试控制台中,打印以下内容

["PLN": CurrencyConverter.CoinInfo(Name: "X",Value: 19.6678),...]

这样,我无法达到硬币的NameValue属性。怎么了?

解决方法

我将进行for循环检查某个键是否包含某些符号。如果可以,我将需要同时访问名称和值

您实际上不需要for循环。由于coinData是字典,因此您可以使用其下标以及可选绑定来执行此操作。例如,要检查键"PLN"是否存在,并访问其名称和值:

if let coinInfo = coinData["PLN"] {
    print(coinInfo.Name)
    print(coinInfo.Value)
} else {
    // "PLN" does not exist
}
,

StoyBoard

enter image description here

代码

import UIKit
import Alamofire

// MARK: - CoinData
struct CoinData: Codable {
    let date,previousDate: String
    let previousURL: String
    let timestamp: String
    let valute: [String: Valute]

    enum CodingKeys: String,CodingKey {
        case date = "Date"
        case previousDate = "PreviousDate"
        case previousURL = "PreviousURL"
        case timestamp = "Timestamp"
        case valute = "Valute"
    }
}

// MARK: - Valute
struct Valute: Codable {
    let id,numCode,charCode: String
    let nominal: Int
    let name: String
    let value,previous: Double

    enum CodingKeys: String,CodingKey {
        case id = "ID"
        case numCode = "NumCode"
        case charCode = "CharCode"
        case nominal = "Nominal"
        case name = "Name"
        case value = "Value"
        case previous = "Previous"
    }
}

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate{
    var getCoinData = [CoinData]()
    var coinNameArr = [String]()
    var coinDataArr = [Valute]()

    @IBOutlet weak var tblDataList: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        getData()
    }

    func getData()
    {
        let url = "https://www.cbr-xml-daily.ru/daily_json.js"
                        
        AF.request(url,method: .get,encoding: URLEncoding.default).responseJSON { response in
            let json = response.data
            do{
                let decoder = JSONDecoder()
                self.getCoinData = [try decoder.decode(CoinData.self,from: json!)]
                let response = self.getCoinData[0]
                if response.valute.count != 0 {
                    self.coinNameArr.removeAll()
                    self.coinDataArr.removeAll()
                    for (coinName,coinData) in response.valute {
                        self.coinNameArr.append(coinName)
                        self.coinDataArr.append(coinData)
                    }
                    self.tblDataList.reloadData()
                } else {
                }
            }catch let err{
                print(err)
            }
        }
    }

    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        return coinDataArr.count
    }

    func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell:coinTblCell = tableView.dequeueReusableCell(withIdentifier: "CellID",for: indexPath as IndexPath) as! coinTblCell
    
        cell.accessoryType = .disclosureIndicator
        cell.tintColor = .black

        let rowData = coinDataArr[indexPath.row]
        cell.lblName.text = rowData.name
        cell.lblValue.text = String(rowData.value)
    
        return cell
    }

}

class coinTblCell: UITableViewCell {
    @IBOutlet weak var lblName: UILabel!
    @IBOutlet weak var lblValue: UILabel!
}