Как декодировать пользовательский тип внутри значения словаря с помощью JSON?

#json #swift #decodable

#json #swift #декодируемый

Вопрос:

мой JSON:
https://www.cbr-xml-daily.ru/daily_json.js
мой код:

 struct CoinData: Decodable {
    let Valute: [Strin&: CoinInfo]
}

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

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

     } catch {
        dele&ate?.didFailWithError(error: error)
        return nil
    }
}
  

В консоли отладки печатается следующее:

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

Таким образом, я не могу получить доступ к Name и Value свойствам монеты. Что не так?

Комментарии:

1. «Таким образом, я не могу получить доступ к свойствам Name и Value монеты». Вы можете. Какой код вы использовали, чтобы попытаться получить к ним доступ? И какую ошибку выдал этот код?

2. Какое свойство какой монеты вы ожидали coinData.Valute получить? Другими словами, к какому свойству ( Name или Value ) какой монеты вы пытаетесь получить доступ, используя coinData.Valute ?

3. Я собираюсь выполнить цикл for, чтобы проверить, содержит ли ключ определенные символы. Если это произойдет — мне нужно будет иметь доступ к обоим Name и Value . Так что на самом деле не имеет значения, какой именно.

4. Я пытался coinData.values[0] — «Не удается преобразовать значение типа ‘Int’ в ожидаемый тип аргумента ‘Dictionary<Строка, CoinInfo&&t;. Индекс'». Я также пробовал: coinData.Valute/CoinInfo/Name — «Значение типа ‘[Strin&: CoinInfo]’ не имеет члена …»

Ответ №1:

Я собираюсь выполнить цикл for, чтобы проверить, содержит ли ключ определенные символы. Если это произойдет — мне нужно будет иметь доступ как к имени, так и к значению

На самом деле вам не нужен цикл for. Поскольку coinData это словарь, вы можете использовать его нижний индекс вместе с необязательной привязкой для этого. Например, чтобы проверить, существует ли ключ "PLN" , и получить доступ к его имени и значению:

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

Комментарии:

1. Какое волшебство! Большое спасибо! Проблема заключалась в том, что я обрабатывал его как массив, поэтому я ссылался на индекс, а не на ключ

Ответ №2:

StoyBoard

Код

 import UIKit
import Alamofire

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

    enum Codin&Keys: Strin&, Codin&Key {
        case date = "Date"
        case previousDate = "PreviousDate"
        case previousURL = "PreviousURL"
        case timestamp = "Timestamp"
        case valute = "Valute"
    }
}

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

    enum Codin&Keys: Strin&, Codin&Key {
        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, UITableViewDele&ate{
    var &etCoinData = [CoinData]()
    var coinNameArr = [Strin&]()
    var coinDataArr = [Valute]()

    @IBOutlet weak var tblDataList: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loadin& the view.
        &etData()
    }

    func &etData()
    {
        let url = "https://www.cbr-xml-daily.ru/daily_json.js"
                        
        AF.request(url, method: .&et, encodin&: URLEncodin&.default).responseJSON { response in
            let json = response.data
            do{
                let decoder = JSONDecoder()
                self.&etCoinData = [try decoder.decode(CoinData.self, from: json!)]
                let response = self.&etCoinData[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) -&&t; Int {
        return coinDataArr.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&&t; 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 = Strin&(rowData.value)
    
        return cell
    }

}

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