【问题标题】:Why JSON data from decoder to become UITableView datasource does not assigns?为什么从解码器变成 UITableView 数据源的 JSON 数据没有分配?
【发布时间】:2020-05-21 06:51:18
【问题描述】:

最近遇到了将新下载的 JSON 数据分配给表视图数据源变量的问题。我想问题很明显,但我的技能不足以收集全局。让我分享一堆代码。

(1) 一个函数从 Open Weather Map API(在单独的类“GetWeather”中定义)检索数据。

func getMowForecast(completion: @escaping ((WeatherForecast?, Bool)) -> Void) {
    let url = URL(string: "http://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=b3d57a41f87619daf456bfefa990fce4&units=metric")!
    let request = URLRequest(url: url)
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let data = data {
            do {
                let json = try JSONDecoder().decode(WeatherForecast.self, from: data)
                completion((json, true))
            } catch {
                print(error)
                completion((nil, false))
            }
        } else {
            print(error)
        }
    }
    task.resume()
}

这里一切正常。 JSON 正确加载并适合数据模型。 下面是要在 tableView 中显示的 JSON 数据的链接:https://pastebin.com/KkXwxYgS

(2) 控制器处理检索到的 JSON 数据以 tableView 格式显示

import UIKit
class ForecastViewController: UITableViewController {

    @IBOutlet weak var tableV: UITableView! // tableView outlet in the IB

    let weatherGetter = GetWeather() // object to handle the JSON retrieval

    var tableData: WeatherForecast? // tableView data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.tableData?.list.count ?? 0
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableVCCell
        cell.dateLabel.text = "\(self.tableData?.list[indexPath.row].dt)"
        cell.tempLabel.text = "\(self.tableData?.list[indexPath.row].main.temp)"
        cell.feelsLikeLabel.text = "\(self.tableData?.list[indexPath.row].main.feels_like)"
        return cell
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.prefersLargeTitles = true
        tableV.delegate = self
        tableV.dataSource = self

        weatherGetter.getMowForecast { (data, status) in
            if let data = data, status {
            } else if status {
                print("-------- Ошибка разбора данных прогноза погоды --------")
            } else {
                print("-------- Ошибка получения данных прогноза погоды --------")
            }
            self.tableData = data
            print(self.tableData)
        }

        print(self.tableData?.list.count) // returns nil

        self.tableData = weatherGetter.getMowForecast(completion: ((tableData, true))) // error - Cannot convert value of type '(WeatherForecast?, Bool)' to expected argument type '((WeatherForecast?, Bool)) -> Void'
    }
    }

问题是 - 表格视图获取 nil 数据源,因此无法加载数据并显示空白屏幕。

我想错误是在范围内 - 我尝试在函数内检索 JSON 数据,但它不会去任何其他地方。我想知道的是 - 为什么将数据分配给 self.tableData 没有任何效果?

你能帮忙吗? 谢谢! 问候

【问题讨论】:

  • 分配self.tabledata = data 后,您需要在闭包中重新加载表格视图。记得在主队列上调度它DispatchQueue.main.async { self.tableV.reloadData() }

标签: ios json swift uitableview


【解决方案1】:

首先删除

罢工>

print(self.tableData?.list.count) // returns nil

self.tableData = weatherGetter.getMowForecast(completion: ((tableData, true))) // error - Cannot convert value of type '(WeatherForecast?, Bool)' to expected argument type '((WeatherForecast?, Bool)) -> Void'

发生错误是因为该方法没有返回任何内容并且完成处理程序语法错误。由于getMowForecast 的异步行为,这两行都毫无意义

其次,我建议将数据源数组声明为表示List 类型的非可选数组。然后你就摆脱了所有那些不必要的选项。

var tableData = [List]()

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

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableVCCell
    let weatherData = self.tableData[indexPath.row]
    cell.dateLabel.text = "\(weatherData.dt)"
    cell.tempLabel.text = "\(weatherData.main.temp)"
    cell.feelsLikeLabel.text = "\(weatherData.main.feels_like)"
    return cell
}

为了能够显示数据——正如其他人已经提到的——你必须在完成处理程序中重新加载表视图。并且仅当statustrue 时才分配数据。

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.navigationBar.prefersLargeTitles = true
    tableV.delegate = self
    tableV.dataSource = self

    weatherGetter.getMowForecast { [weak self] (data, status) in
        if let data = data, status {
           self?.tableData = data.list
           DispatchQueue.main.async {
              self?.tableV.reloadData()
           }
        } else if status {
            print("-------- Ошибка разбора данных прогноза погоды --------")
        } else {
            print("-------- Ошибка получения данных прогноза погоды --------")
        }            
    }
}

并考虑到消息 Ошибка разбора данных прогноза погоды 将永远不会显示。

【讨论】:

    【解决方案2】:

    你需要在回调中重新加载表,因为它是异步的

     self.tableData = data
     print(self.tableData) 
     DispatchQueue.main.async { self.tableV.reloadData() } 
    

    【讨论】:

      猜你喜欢
      • 2020-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多