Swift JSON Проблема синтаксического анализа, не может вернуть правильное количество ячеек - PullRequest
0 голосов
/ 06 апреля 2020

Я столкнулся с проблемой, так как не могу вернуть количество ячеек из объекта fetchedData. Я могу напечатать массив с данными, но я не могу заполнить ячейки. Было бы здорово, если бы кто-нибудь мог помочь мне решить эту загадку:)

Вот моя модель:

import Foundation

struct ExchangeRateModel: Codable {
  let table: String
  let no: String
  let effectiveDate: String
  let rates: [Rate]
}

struct Rate: Codable {
  let currency: String
  let code: String
  let mid: Double
}

и rootV C

import UIKit

class RootViewController: UIViewController {

  private let cellID = "cell"
  private let tabelType = ["a","b","c"]
  private let exchangeTabels = ["Tabela A", "Tabela B", "Tabela C"]
  private var currentTable = "a"
  private let urlString = "https://api.nbp.pl/api/exchangerates/tables/"
  var fetchedData = [ExchangeRateModel]()


  private let tableView: UITableView = {
    let tabel = UITableView()
    return tabel
  }()

  override func viewDidLoad() {
    super.viewDidLoad()
    configureNavBar()
    configureView()
    configureTable()
    performeRequest()
    tableView.reloadData()
  }

  private func configureNavBar(){
    title = "KURSY WALUT NBP"
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Tabele", style: .plain, target: self, action: #selector(tabeleTapped))
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(refreshTapped))
  }

  @objc private func tabeleTapped(){
    let ac = UIAlertController(title: "Zmień tabele kursów", message: nil, preferredStyle: .actionSheet)
    for table in exchangeTabels {
      ac.addAction(UIAlertAction(title: table, style: .default, handler: changeTable))
    }
    present(ac, animated: true)
  }

  func changeTable(action: UIAlertAction){
    if action.title == exchangeTabels[0]{
      currentTable = tabelType[0]
      tableView.reloadData()
    } else if action.title == exchangeTabels[1] {
      currentTable = tabelType[1]
      tableView.reloadData()
    } else {
      currentTable = tabelType[2]
      tableView.reloadData()
    }
  }

  @objc private func refreshTapped(){
    tableView.reloadData()
  }

  private func configureView(){
    view.backgroundColor = .white
    view.addSubview(tableView)
    tableView.translatesAutoresizingMaskIntoConstraints = false
    tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
  }

  private func configureTable(){
    tableView.delegate = self
    tableView.dataSource = self
    tableView.rowHeight = 50
    tableView.register(TabelTableViewCell.self, forCellReuseIdentifier: cellID)
  }

  private func performeRequest(){
    let urlString = "\(self.urlString)\(currentTable)"
    let url = URL(string: urlString)
    print("URL: \(url!)")
    guard url != nil else { return }
    let session = URLSession(configuration: .default)
    let dataTask = session.dataTask(with: url!) { (data, response, error) in
      if error == nil && data != nil {
        let decoder = JSONDecoder()
        do {
          let decodedData = try decoder.decode([ExchangeRateModel].self, from: data!)
          self.fetchedData = decodedData
          print(self.fetchedData)
        } catch {
          print(error)
        }
      }
    }
    DispatchQueue.main.async {
      dataTask.resume()
      self.tableView.reloadData()
    }
  }
}

extension RootViewController: UITableViewDelegate, UITableViewDataSource {
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print(fetchedData.count)
    return fetchedData.count
  }

Здесь я Я не уверен, как вернуть эти данные

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TabelTableViewCell
    cell.currencyNameLabel.text = fetchedData[indexPath.row].rates[indexPath.row].currency
    cell.currencyCodeLabel.text = fetchedData[indexPath.row].rates[indexPath.row].code
    cell.effectiveDateLabel.text = fetchedData[indexPath.row].effectiveDate
    cell.midRateLabel.text = String(fetchedData[indexPath.row].rates[indexPath.row].mid)
    return cell
  }

  func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    let nextVC = CurrencyViewController()
    navigationController?.pushViewController(nextVC, animated: true)
  }
}

Спасибо всем заранее!

Ответы [ 3 ]

0 голосов
/ 06 апреля 2020

Вы не перезагрузили таблицу после получения ответа от вызова API. внутри ответного обратного вызова, где вы печатаете массив ответов, вы должны перезагрузить просмотр таблицы.

do { let decodedData = try decoder.decode([ExchangeRateModel].self, from: data!) self.fetchedData = decodedData print(self.fetchedData) DispatchQueue.main.async { self.tableView.reloadData() } } catch { print(error) }

0 голосов
/ 06 апреля 2020

Я также добавил DispatchQueue и обновил все остальные места. См. Ниже:

 private func performeRequest(){
    let urlString = "\(self.urlString)\(currentTable)"
    let url = URL(string: urlString)
    print("URL: \(url!)")
    guard url != nil else { return }
    let session = URLSession(configuration: .default)
    let dataTask = session.dataTask(with: url!) { (data, response, error) in
      if error == nil && data != nil {
        let decoder = JSONDecoder()
        do {
          let decodedData = try decoder.decode([ExchangeRateModel].self, from: data!)
          self.fetchedData = decodedData
          print(self.fetchedData)
          DispatchQueue.main.async {
            self.tableView.reloadData()
          }
        } catch {
          print(error)
        }
      }
    }
    dataTask.resume()
  }
}

, а также таблицу:

extension RootViewController: UITableViewDelegate, UITableViewDataSource {
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print(fetchedData.count)
    return fetchedData[0].rates.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TabelTableViewCell
    cell.currencyNameLabel.text = fetchedData[0].rates[indexPath.row].currency
    cell.currencyCodeLabel.text = fetchedData[0].rates[indexPath.row].code
    cell.effectiveDateLabel.text = fetchedData[0].effectiveDate
    cell.midRateLabel.text = String(fetchedData[0].rates[indexPath.row].mid)
    return cell
  }

  func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    let nextVC = CurrencyViewController()
    navigationController?.pushViewController(nextVC, animated: true)
  }
}

, и я все еще получаю эту ошибку.

0 голосов
/ 06 апреля 2020

Необходимо перезагрузить просмотр таблицы после получения значения с сервера.

Попробуйте этот код

private func performeRequest(){
    let urlString = "\(self.urlString)\(currentTable)"
    let url = URL(string: urlString)
    print("URL: \(url!)")
    guard url != nil else { return }
    let session = URLSession(configuration: .default)
    let dataTask = session.dataTask(with: url!) { (data, response, error) in
      if error == nil && data != nil {
        let decoder = JSONDecoder()
        do {
          let decodedData = try decoder.decode([ExchangeRateModel].self, from: data!)
          self.fetchedData = decodedData
          print(self.fetchedData)
          DispatchQueue.main.async {
              self.tableView.reloadData()
           }
        } catch {
          print(error)
        }
      }
    }
    dataTask.resume()
  }

json содержит только один ExchangeRateModel в массиве.

Похоже, вы хотите показать цены. Вам нужно return fetchedData[0].rates.count вместо return fetchedData.count

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     if fetchedData.count > 0 {
          return fetchedData[0].rates.count
     }
     return 0
  }

Также вам необходимо обновить cellForRowAtIndexPath метод, подобный этому

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TabelTableViewCell
    cell.currencyNameLabel.text = fetchedData[0].rates[indexPath.row].currency
    cell.currencyCodeLabel.text = fetchedData[0].rates[indexPath.row].code
    cell.effectiveDateLabel.text = fetchedData[0].effectiveDate
    cell.midRateLabel.text = String(fetchedData[0].rates[indexPath.row].mid)
    return cell
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...